zoukankan      html  css  js  c++  java
  • zju2676 Network Wars 分数规划+网络流

    题意:给定无向图,每条边有权值,求该图的一个割集,是的该割集的平均边权最小

    Amber的《最小割模型在信息学竞赛中的应用》中讲的很清楚了。

    二分答案k,对每条边进行重新赋值为原边权-k,求最大流,

    可看这里:http://hi.baidu.com/buaa_babt/item/a08fbb45599dc722fb89602a

     二分枚举当前的平均边长l,对于边权<=l的直接加入当前最优割集,边权>l的将容量设为边权-l,加入到网络中,求出最小割的和sum,sum加上刚刚那些小于l的边(也是边权-l),如果大于0就意味着l不可作为最小平均边权,小于0就可以,当等于0时直接输出即可。一定要注意精度

     注意是无向图,还有就是求st割,求解答案。

    #define inf 0x3f3f3f3f
    #define maxm 100000
    #define maxn 10000
    #define eps 1e-9
    struct node
    {
      int u ;
      int v,next,id;
      double w;
      void init(int u1,int v1,double w1)
      {
        u = u1;
        v = v1;
        w = w1;
      }
    };
    node e1[maxn];
    int head[maxn];
    int cnt ;
    int cnt1;
    node edge[maxn];
    int sgn(double x) {         //return -1 0 1
      return x < -eps ? -1 : x > eps;
    }
    void init()
    {
      memset(head,-1,sizeof(head));
      cnt = 0 ;
    }
    void add(int u,int v,int id,double w)
    {
      edge[cnt].u = u;
      edge[cnt].v = v;
      edge[cnt].w = w;
      edge[cnt].id = id;
      edge[cnt].next = head[u];
      head[u] = cnt ++ ;
    
      edge[cnt].u = v;
      edge[cnt].v = u;
      edge[cnt].w = 0;
      edge[cnt].id = id;
      edge[cnt].next = head[v];
      head[v] = cnt ++ ;
    }
    
    int dis[maxn];
    int pre[maxn],cur[maxn],gap[maxn];
    int s,t,nn;
    
    int sap()
    {
      double flow,aug;
      int u;
      int flag;
      int i;
      flow=0;
      aug=inf;
      for(i=0; i<nn; i++)
      {
        cur[i]=head[i];
        gap[i]=0;
        dis[i]=0;
      }
      gap[s]=nn;
      u=s;
      pre[s]=s;
      while(dis[s]<nn)
      {
        flag=0;
        for(int &j=cur[u]; j!=-1; j=edge[j].next)
        {
          //cur[u]=j;
          int v=edge[j].v;
          if(edge[j].w>0&&dis[u]==dis[v]+1)
          {
            flag=1;
            if(edge[j].w<aug)aug=edge[j].w;
            pre[v]=u;
            u=v;
            if (u==t)
            {
              flow+=aug;
              while(u!=s)
              {
                u=pre[u];
                edge[cur[u]].w-=aug;
                edge[cur[u]^1].w+=aug;
                //why?解释偶数异或1为偶数+1,奇数异或1为奇数-1,
                //显然我们存的边是从0开始存的,
                //所以偶数,偶数+1是残量网格中的两条边(无向边)
              }
              aug=inf;
            }
            break;
          }
        }
        if (flag) continue;
        int mindis=nn;
        for(int j=head[u]; j!=-1; j=edge[j].next)
        {
          int v=edge[j].v;
          if (edge[j].w>0&&dis[v]<mindis)
          {
            mindis=dis[v];
            cur[u]=j;
          }
        }
        if (--gap[dis[u]]==0)//间隙优化
        {
          break;
        }
        dis[u]=mindis+1;
        gap[dis[u]]++;
        u=pre[u];
      }
      return flow;
    }
    bool xxx[maxn];
    int n,m;
    double judge(double lda)
    {
      memset(xxx,0,sizeof(xxx));
      init();
      double res = 0.0;
      for(int i = 1; i <= m  ; i ++)
      {
        double tmp ;
        tmp = e1[i].w - lda;
        if( tmp >=0 )
          add(e1[i].u,e1[i].v,i,tmp) , add(e1[i].v,e1[i].u,i,tmp); // 注意
        else
        {
          res += tmp;
          xxx[i] = 1 ;
        }
        //if(sgn(tmp) < 0 )
        //    res += tmp ;
        //else add(e1[i].u,e1[i].v,i,tmp);
      }
      s = 1;
      t = n ;
      nn = t + 2;
      res += sap();
      return res;
    }
    queue<int> q;
    int col[maxn];
    bool vis[maxn];
    void bfs(int st,int color)
    {
      memset(vis,0,sizeof(vis));
      memset(col,0,sizeof(col));
      while(!q.empty()) q.pop();
      q.push(st);
      vis[st] = 1;
      col[st] = color;
      while(!q.empty())
      {
        int u = q.front();
        q.pop();
        for(int i = head[u] ; i != -1; i = edge[i].next)
        {
          int v = edge[i].v;
          if(sgn(edge[i].w) > 0 && vis[v] == 0 )
          {
            vis[v] = 1;
            col[v] = color;
            q.push(v);
          }
        }
      }
      return ;
    }
    vector<int> ans ;
    void getst(double lda)
    {
      bfs(1,1);
      ans.clear();
      for(int i = 1 ; i <= m ; i ++ )     // 注意 
      {
        if(!xxx[i])
        {
          if(col[e1[i].u] != col[e1[i].v] )
          {
            ans.push_back(i);
          }
        }
        else ans.push_back(i);
      }
      int size = ans.size();
      sort(ans.begin(),ans.end());
      printf("%d
    ",size);
      for(int i = 0; i < size ; i++ )
      {
        printf("%d",ans[i]);
        if(i != size - 1 ) printf(" ");
        else printf("
    ");
      }
    }
    int main()
    {
      int cas;
      cas = 0 ;
      while(scanf("%d%d",&n,&m)!=EOF)
      {
        cnt1 = 1 ;
        int u,v;
        double w;
        double L,R;
        L = eps;
        for(int i = 1 ; i <= m; i ++ )
        {
          scanf("%d%d%lf",&u,&v,&w);
          e1[i].init(u,v,w);
          R = max(R , w);
        }
        double mid ;
        for(int i = 0 ; i < 101 ; i ++ )
          // while( R - L > eps )
        {
          mid = ( L + R ) / 2.0;
          double tmp = judge(mid);
          if(sgn(tmp ) > 0 )    // 判断
            L = mid + eps;
          else R = mid;
        }
        if(cas != 0 ) printf("
    ");
        cas ++ ;
        judge(L);
        getst(L);
      }
      return 0;
    }    
    View Code
  • 相关阅读:
    迭代器和生成器
    函数嵌套
    页面调用dll
    C++MFC之picture control控件铺满图片
    C++中去掉string字符串中的 等
    C++之map使用
    C++之条形码,windows下zint库的编译及应用(二)
    C++之条形码,windows下zint库的编译及应用(一)
    C++通过HTTP请求Get或Post方式请求Json数据(转)
    从长字符串中获取想要的字符串
  • 原文地址:https://www.cnblogs.com/jh818012/p/3290294.html
Copyright © 2011-2022 走看看