ZOJ 2532 网络流最小割

求最小割的问题。

题意:已知网络中有n个源点,m的中转站(也就是节点),一个汇点(编号为0)。给出网络,求一些边(增大这个边就可以增大汇点流量的边)。

思路:一开始代码只找了有流=0就加入输出数组的情况,然而忽略了流向一条S->T的流有多个边权=0的情况,此时只增大一条边的值是没用的。

所以除了用一次最大流算法后,还需要用两次dfs分别从超级源点S和汇点T开始搜索,这样就可以把有多个0-0-0和单个边权为0的情况判断出来。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <queue>
  6 #include <stack>
  7 #include <map>
  8 #include <set>
  9 #include <vector>
 10 #include <algorithm>
 11 using namespace std;
 12 const int INF = 0x3f3f3f3f;
 13 typedef struct node
 14 {
 15     int u;
 16     int v;
 17     int Flow;
 18     int next;
 19 }Line;
 20 Line Li[2200];
 21 int Head[110],top;
 22 int vis[110],ans[110];
 23 bool vis1[110],vis2[110];
 24 int n,m,l;
 25 int s,t;
 26 void AddEdge(int u,int v,int f)
 27 {
 28     Li[top].v=v; Li[top].u=u;
 29     Li[top].Flow=f;
 30     Li[top].next=Head[u];
 31     Head[u]=top++;
 32 }
 33 bool BFS()
 34 {
 35     memset(vis,-1,sizeof(vis));
 36     vis[s]=0;
 37     queue<int >Q;
 38     Q.push(s);
 39     while(!Q.empty())
 40     {
 41         int u=Q.front();
 42         Q.pop();
 43         for(int i=Head[u];i!=-1;i=Li[i].next)
 44         {
 45             if(Li[i].Flow&&vis[Li[i].v]==-1)
 46             {
 47                 vis[Li[i].v]=vis[u]+1;
 48                 Q.push(Li[i].v);
 49             }
 50         }
 51     }
 52     return vis[t]!=-1;
 53 }
 54 int DFS(int u,int f)
 55 {
 56     if(u==t)
 57     {
 58         return f;
 59     }
 60     int ans=0;
 61     for(int i=Head[u];i!=-1;i=Li[i].next)
 62     {
 63         if(Li[i].Flow&&vis[Li[i].v]==vis[u]+1)
 64         {
 65             int d=DFS(Li[i].v,min(f,Li[i].Flow));
 66             f-=d;
 67             Li[i].Flow-=d;
 68             Li[i^1].Flow+=d;
 69             ans+=d;
 70         }
 71     }
 72     return ans;
 73 }
 74 void dfs(int u,bool *vist,int op)
 75 {
 76     vist[u]=true;
 77     for(int i=Head[u];i!=-1;i=Li[i].next)
 78     {
 79         if(!vist[Li[i].v]&&Li[i^op].Flow!=0)
 80         {
 81             dfs(Li[i].v,vist,op);
 82         }
 83     }
 84 }
 85 void Dinic()//网络流进行增广
 86 {
 87     int ans;
 88     while(BFS())
 89     {
 90         ans=DFS(s,INF);
 91         printf("!\n");
 92     }
 93 }
 94 int main()
 95 {
 96     while(~scanf("%d %d %d",&n,&m,&l))
 97     {
 98         if(n+m+l==0)
 99         {
100             break;
101         }
102         s=n+m+1;//源点
103         t=0;//汇点
104         memset(Head,-1,sizeof(Head));
105         int a,b,c;
106         top = 0;
107         for(int i=0;i<l;i++)
108         {
109             scanf("%d %d %d",&a,&b,&c);
110             AddEdge(a,b,c);//建立边,正向为c,负向为0
111             AddEdge(b,a,0);
112         }
113         for(int i=1;i<=n;i++)
114         {
115             AddEdge(s,i,INF);
116             AddEdge(i,s,0);//建立城市与源点之间的边,权值为INF
117         }
118         Dinic();
119         memset(vis1,false,sizeof(vis1));
120         memset(vis2,false,sizeof(vis2));
121         dfs(s,vis1,0);//从源点向汇点搜索,标记还有剩余流的点
122         dfs(t,vis2,1);//从汇点到源点搜索,标记还有剩余流的点
123         int num=0;
124         for(int i=0;i<l;i++)
125         {
126             if(Li[i<<1].Flow==0&&vis1[Li[i<<1].u]&&vis2[Li[i<<1].v])
127                 ans[num++]=i+1;//如果一条边的u与v都被标记,表明s->u,v->t,但是这条边是满流,所以提升这条边。
128         }
129         if(num)
130         {
131             for(int i=0;i<num;i++)
132             {
133                 if(i)printf(" ");
134                 printf("%d",ans[i]);
135             }
136         }
137         printf("\n");
138     }
139     return 0;
140 }
View Code

代码转自(https://blog.csdn.net/huayunhualuo/article/details/50554800)这个题解的板子跟我的差不多就转了

posted @ 2018-07-30 16:00  llllrj  阅读(193)  评论(0编辑  收藏  举报