zoukankan      html  css  js  c++  java
  • hdu2435最大流最小割

    2435  There is a war


    题意:
          给你一个有向图,其中可以有一条边是无敌的,这条边可以是图中的边,也可以是自己任意加上去的图中没有的边,这条无敌的边不可以摧毁,让1和n无法连通的最大摧毁费用,就是1到n的最小割中的最大的那个,这个题卡了好几天,一开始是各种方法各种wa,后来无意中发现自己犯了个sb错误,结果改正后以前的各种方法各种ac,比赛要是碰到这样的事估计就跪了...


    思路:
         首先能确定的就是题目要求咱们就最小割(最大流 = 最小割),但关键是有那么一条无坚不摧的nb道路,所以一开始的想法肯定是暴力枚举N*N的边,直接TLE出翔了,那么就优化,记得以前的一道题目 给你一个图求删除其中一条边最短路中最大的那个,答案是只枚举最短路上的边就可以了, 这个题目也是类似,只要枚举最小割后两个集合的点组成的边就行了,因为假如点a和点b是一个集合的,那么把边ab变成无敌的没有意思,最小割的值不会改变,,那么怎么吧分成两个集合呢,两种方法,一个是深搜,这个方法容易理解,先跑一遍最大流,然后从点1开始深搜,如果当前点走过或者没有流量了(跑完一遍最大流后的流量),直接continue,这样被mark的点就是左集合的点,剩下的就是右集合的点,还有一种方法就是直接看DINIC后的deep数组,如果不等于-1就是左集合的,否则的就是右集合的,这个我结论是网上的,我还不知道为什么,分成两个集合后就可以枚举两个集合的点建枚举的边了,这块也有两个方法,一个就是之前不是跑一边最大流了吗,加上当前枚举边,直接在残余网络上跑,取得最大的max最后输出一开始那个最大流maxflow+max,(记得每次跑之前都还原成第一次跑完的残余网路),第二种方法就是直接重新建边,一开始的时候吧m条边记录下来,每次枚举都重新建图,然后加上枚举的边跑,最后输出的是最大流中最大的那个maxflow.下面是三种方法的代码..




    深搜找源集和汇集,在残余网络上跑 15ms AC
    #include<stdio.h>
    #include<string.h>
    #include<queue>


    #define N_node 120

    #define N_edge 22000
    #define inf 1000000000


    using namespace std;


    typedef struct

    {
       int to ,next ,cost;
    }STAR;
    typedef struct
    {
       int x ,t;
    }DEP;


    STAR E[N_edge] ,E_[N_edge];
    DEP xin ,tou;
    int list[N_node] ,list1[N_node] ,tot;
    int list2[N_node];
    int deep[N_node];
    int mks[N_node] ,mks_;
    int mkh[N_node] ,mkh_;
    int mark[N_node];


    void add(int a ,int b ,int c)
    {
       E[++tot].to = b;
       E[tot].cost = c;
       E[tot].next = list[a];
       list[a] = tot;
       
       E[++tot].to = a;
       E[tot].cost = 0;
       E[tot].next = list[b];
       list[b] = tot;
    }


    int minn(int a ,int b)
    {
       return a < b ? a : b;
    }


    bool BFS_DEEP(int s ,int t ,int n)
    {
        memset(deep ,255 ,sizeof(deep));
        deep[s] = 0;
        xin.x = s;
        xin.t = 0;
        queue<DEP>q;
        q.push(xin);
        while(!q.empty())
        {
          tou = q.front();
          q.pop();
          for(int k = list[tou.x] ;k ;k = E[k].next)
          {
             xin.x = E[k].to;
             xin.t = tou.t + 1;
             if(deep[xin.x] != -1 || !E[k].cost)
             continue;
             deep[xin.x] = xin.t;
             q.push(xin);
          }
       }
       for(int i = 0 ;i <= n ;i ++)
       list1[i] = list[i];
       return deep[t] != -1;
    }


    int DFS_MAX_FLOW(int s ,int t ,int flow)
    {
       if(s == t) return flow;
       int nowflow = 0;
       for(int k = list1[s] ;k ;k = E[k].next)
       {
          list1[s] = k;
          int to = E[k].to;
          int c = E[k].cost;
          if(deep[to] != deep[s] + 1||!E[k].cost)
          continue;
          int tmp = DFS_MAX_FLOW(to ,t ,minn(c ,flow - nowflow));
          nowflow += tmp;
          E[k].cost -= tmp;
          E[k^1].cost += tmp;
          if(nowflow == flow)
          break;
       }
       if(!nowflow)
       deep[s] = 0;
       return nowflow;
    }


    int DINIC(int s ,int t ,int n)
    {
       int ans = 0;
       while(BFS_DEEP(s ,t ,n))
       {
          ans += DFS_MAX_FLOW(s ,t ,inf);
       }
       return ans;
    }


    void DFS(int s)
    {
       for(int k = list[s] ;k ;k = E[k].next)
       {
          int to = E[k].to;
          if(mark[to] || !E[k].cost)
          continue;
          mark[to] = 1;
          DFS(to);
       }
       return ;
    }


    int main ()
    {
       int n ,m ,i ,j ,t;
       int a ,b ,c;
       scanf("%d" ,&t);
       while(t--)
       {
          memset(list ,0 ,sizeof(list));
          tot = 1;
          scanf("%d %d" ,&n ,&m);
          for(i = 1 ;i <= m ;i ++)
          {
             scanf("%d %d %d" ,&a ,&b ,&c);
             add(a ,b ,c);
          }
          int ans = DINIC(1 ,n ,n);
          mks_ = mkh_ = 0;
          memset(mark ,0 ,sizeof(mark));
          mark[1] = 1;
          DFS(1);
          for(i = 2 ;i < n ;i ++)
          if(mark[i]) mks[++mks_] = i;
          else mkh[++mkh_] = i;
          
          for(i = 1 ;i <= tot ;i ++)
          E_[i] = E[i];
          int mktot = tot;
          for(i = 1 ;i <= n ;i ++)
          list2[i] = list[i];
          
          int max = 0;
          for(i = 1 ;i <= mks_ ;i ++)
          for(j = 1 ;j <= mkh_ ;j ++)
          {
             a = mks[i] ,b = mkh[j];
             for(int k = 1 ;k <= mktot ;k ++)
             E[k] = E_[k];
             memset(list ,0 ,sizeof(list));
             for(int k = 1 ;k <= n ;k ++)
             list[k] = list2[k];
             tot = mktot;
             add(a ,b ,inf);
             int tmp = DINIC(1 ,n ,n);
             if(max < tmp) max = tmp;
          }
          printf("%d " ,ans + max);
       }
       return 0;
    }
             
             
          
          
    根据deep数组找源集和汇集,在残余网络上跑 31ms AC

    #include<stdio.h>
    #include<string.h>
    #include<queue>


    #define N_node 120
    #define N_edge 22000
    #define inf 1000000000


    using namespace std;


    typedef struct
    {
       int to ,next ,cost;
    }STAR;
    typedef struct
    {
       int x ,t;
    }DEP;


    STAR E[N_edge] ,E_[N_edge];
    DEP xin ,tou;
    int list[N_node] ,list1[N_node] ,tot;
    int list2[N_node];
    int deep[N_node];
    int mks[N_node] ,mks_;
    int mkh[N_node] ,mkh_;


    void add(int a ,int b ,int c)
    {
       E[++tot].to = b;
       E[tot].cost = c;
       E[tot].next = list[a];
       list[a] = tot;
       
       E[++tot].to = a;
       E[tot].cost = 0;
       E[tot].next = list[b];
       list[b] = tot;
    }


    int minn(int a ,int b)
    {
       return a < b ? a : b;
    }


    bool BFS_DEEP(int s ,int t ,int n)
    {
        memset(deep ,255 ,sizeof(deep));
        deep[s] = 0;
        xin.x = s;
        xin.t = 0;
        queue<DEP>q;
        q.push(xin);
        while(!q.empty())
        {
          tou = q.front();
          q.pop();
          for(int k = list[tou.x] ;k ;k = E[k].next)
          {
             xin.x = E[k].to;
             xin.t = tou.t + 1;
             if(deep[xin.x] != -1 || !E[k].cost)
             continue;
             deep[xin.x] = xin.t;
             q.push(xin);
          }
       }
       for(int i = 0 ;i <= n ;i ++)
       list1[i] = list[i];
       return deep[t] != -1;
    }


    int DFS_MAX_FLOW(int s ,int t ,int flow)
    {
       if(s == t) return flow;
       int nowflow = 0;
       for(int k = list1[s] ;k ;k = E[k].next)
       {
          list1[s] = k;
          int to = E[k].to;
          int c = E[k].cost;
          if(deep[to] != deep[s] + 1||!E[k].cost)
          continue;
          int tmp = DFS_MAX_FLOW(to ,t ,minn(c ,flow - nowflow));
          nowflow += tmp;
          E[k].cost -= tmp;
          E[k^1].cost += tmp;
          if(nowflow == flow)
          break;
       }
       if(!nowflow)
       deep[s] = 0;
       return nowflow;
    }


    int DINIC(int s ,int t ,int n)
    {
       int ans = 0;
       while(BFS_DEEP(s ,t ,n))
       {
          ans += DFS_MAX_FLOW(s ,t ,inf);
       }
       return ans;
    }


    int main ()
    {
       int n ,m ,i ,j ,t;
       int a ,b ,c;
       scanf("%d" ,&t);
       while(t--)
       {
          memset(list ,0 ,sizeof(list));
          tot = 1;
          scanf("%d %d" ,&n ,&m);
          for(i = 1 ;i <= m ;i ++)
          {
             scanf("%d %d %d" ,&a ,&b ,&c);
             add(a ,b ,c);
          }
          int ans = DINIC(1 ,n ,n);
          mks_ = mkh_ = 0;
          for(i = 2 ;i < n ;i ++)
          if(deep[i] != -1) mks[++mks_] = i;
          else mkh[++mkh_] = i;
          
          for(i = 1 ;i <= tot ;i ++)
          E_[i] = E[i];
          int mktot = tot;
          for(i = 1 ;i <= n ;i ++)
          list2[i] = list[i];
          
          int max = 0;
          for(i = 1 ;i <= mks_ ;i ++)
          for(j = 1 ;j <= mkh_ ;j ++)
          {
             a = mks[i] ,b = mkh[j];
             for(int k = 1 ;k <= mktot ;k ++)
             E[k] = E_[k];
             memset(list ,0 ,sizeof(list));
             for(int k = 1 ;k <= n ;k ++)
             list[k] = list2[k];
             tot = mktot;
             add(a ,b ,inf);
             int tmp = DINIC(1 ,n ,n);
             if(max < tmp) max = tmp;
          }
          printf("%d " ,ans + max);
       }
       return 0;
    }
             
    直接重新建图,深搜找源集和汇集(容易理解) 15msAC


    #include<stdio.h>
    #include<string.h>
    #include<queue>


    #define N_node 120
    #define N_edge 22000
    #define inf 1000000000


    using namespace std;


    typedef struct
    {
       int to ,next ,cost;
    }STAR;
    typedef struct
    {
       int x ,t;
    }DEP;


    typedef struct
    {
       int a ,b ,c;
    }EDGE;


    STAR E[N_edge];
    EDGE edge[N_edge];
    DEP xin ,tou;
    int list[N_node] ,list1[N_node] ,tot;
    int deep[N_node];
    int mks[N_node] ,mks_;
    int mkh[N_node] ,mkh_;
    int mark[N_node];


    void add(int a ,int b ,int c)
    {
       E[++tot].to = b;
       E[tot].cost = c;
       E[tot].next = list[a];
       list[a] = tot;
       
       E[++tot].to = a;
       E[tot].cost = 0;
       E[tot].next = list[b];
       list[b] = tot;
    }


    int minn(int a ,int b)
    {
       return a < b ? a : b;
    }


    bool BFS_DEEP(int s ,int t ,int n)
    {
        memset(deep ,255 ,sizeof(deep));
        deep[s] = 0;
        xin.x = s;
        xin.t = 0;
        queue<DEP>q;
        q.push(xin);
        while(!q.empty())
        {
          tou = q.front();
          q.pop();
          for(int k = list[tou.x] ;k ;k = E[k].next)
          {
             xin.x = E[k].to;
             xin.t = tou.t + 1;
             if(deep[xin.x] != -1 || !E[k].cost)
             continue;
             deep[xin.x] = xin.t;
             q.push(xin);
          }
       }
       for(int i = 0 ;i <= n ;i ++)
       list1[i] = list[i];
       return deep[t] != -1;
    }


    int DFS_MAX_FLOW(int s ,int t ,int flow)
    {
       if(s == t) return flow;
       int nowflow = 0;
       for(int k = list1[s] ;k ;k = E[k].next)
       {
          list1[s] = k;
          int to = E[k].to;
          int c = E[k].cost;
          if(deep[to] != deep[s] + 1||!E[k].cost)
          continue;
          int tmp = DFS_MAX_FLOW(to ,t ,minn(c ,flow - nowflow));
          nowflow += tmp;
          E[k].cost -= tmp;
          E[k^1].cost += tmp;
          if(nowflow == flow)
          break;
       }
       if(!nowflow)
       deep[s] = 0;
       return nowflow;
    }


    int DINIC(int s ,int t ,int n)
    {
       int ans = 0;
       while(BFS_DEEP(s ,t ,n))
       {
          ans += DFS_MAX_FLOW(s ,t ,inf);
       }
       return ans;
    }


    void DFS(int s)
    {
       for(int k = list[s] ;k ;k = E[k].next)
       {
          int to = E[k].to;
          if(mark[to] || !E[k].cost)
          continue;
          mark[to] = 1;
          DFS(to);
       }
       return ;
    }


    int main ()
    {
       int n ,m ,i ,j ,t;
       int a ,b ,c;
       scanf("%d" ,&t);
       while(t--)
       {
          memset(list ,0 ,sizeof(list));
          tot = 1;
          scanf("%d %d" ,&n ,&m);
          for(i = 1 ;i <= m ;i ++)
          {
             scanf("%d %d %d" ,&a ,&b ,&c);
             add(a ,b ,c);
             edge[i].a = a ,edge[i].b = b ,edge[i].c = c;
          }
          int ans = DINIC(1 ,n ,n);
          mks_ = mkh_ = 0;
          memset(mark ,0 ,sizeof(mark));
          mark[1] = 1;
          DFS(1);
          for(i = 2 ;i < n ;i ++)
          if(mark[i]) mks[++mks_] = i;
          else mkh[++mkh_] = i;
          for(i = 1 ;i <= mks_ ;i ++)
          for(j = 1 ;j <= mkh_ ;j ++)
          {
             a = mks[i] ,b = mkh[j];
             memset(list ,0 ,sizeof(list));
             tot = 1;
             for(int k = 1 ;k <= m ;k ++)
             add(edge[k].a ,edge[k].b ,edge[k].c);
             add(a ,b ,inf);
             int tmp = DINIC(1 ,n ,n);
             if(ans < tmp) ans = tmp;
          }
          printf("%d " ,ans);
       }
       return 0;
    }

    
    

  • 相关阅读:
    算法竞赛入门经典习题2-3 韩信点兵
    ios入门之c语言篇——基本函数——5——素数判断
    ios入门之c语言篇——基本函数——4——数值交换函数
    144. Binary Tree Preorder Traversal
    143. Reorder List
    142. Linked List Cycle II
    139. Word Break
    138. Copy List with Random Pointer
    137. Single Number II
    135. Candy
  • 原文地址:https://www.cnblogs.com/csnd/p/12063235.html
Copyright © 2011-2022 走看看