hdoj Flow Problem 3549 (最大流入门)

来源:互联网 发布:小学生编程需求 编辑:程序博客网 时间:2024/06/03 05:50

Flow Problem

Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 11469    Accepted Submission(s): 5434


Problem Description
Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph.

Input
The first line of input contains an integer T, denoting the number of test cases.
For each test case, the first line contains two integers N and M, denoting the number of vertexes and edges in the graph. (2 <= N <= 15, 0 <= M <= 1000)
Next M lines, each line contains three integers X, Y and C, there is an edge from X to Y and the capacity of it is C. (1 <= X, Y <= N, 1 <= C <= 1000)

Output
For each test cases, you should output the maximum flow from source 1 to sink N.

Sample Input
23 21 2 12 3 13 31 2 12 3 11 3 1

Sample Output
Case 1: 1Case 2: 2
 
//http://www.cnblogs.com/acSzz/archive/2012/09/13/2683820.html
// Ford-Fulkerson算法
#include<stdio.h>#include<string.h>#include<algorithm>#include<queue>#define INF 0x3f3f3f3f#define N 22using namespace std;int p[N];bool vis[N];int map[N][N];int s,e;int n,m;bool bfs(){queue<int>q;memset(p,0,sizeof(p));memset(vis,false,sizeof(vis));vis[s]=1;q.push(s);while(!q.empty()){int ss=q.front();q.pop();if(ss==e)return true;//如果找到一条从1到n的路。 for(int i=2;i<=n;i++){if(!vis[i]&&map[ss][i])//如果可到达,但还没访问,遍历所有与i相连的城市 {q.push(i);p[i]=ss;//p[]数组里存放父节点 vis[i]=1;}}}return false;//找不到 }int maxflow(){int ans=0;//记录最大流 while(1){if(!bfs())//如果没有从1到n的路 return ans;//直接输出流量 int mm=INF;for(int i=e;i!=s;i=p[i])//从终点往起点找(从最小子孙往祖宗找) mm=min(mm,map[p[i]][i]);//找到关系网中的最小的残留量。 for(int i=e;i!=s;i=p[i])//逐个更新 {map[p[i]][i]-=mm;//正着的(父到子) map[i][p[i]]+=mm;//反着的(子到父) }ans+=mm;//更新最大流 }}int main(){int t;int T=1;int u,v,w;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);s=1;e=n;memset(map,0,sizeof(map));while(m--){scanf("%d%d%d",&u,&v,&w);map[u][v]+=w;//每条边赋初值 }printf("Case %d: %d\n",T++,maxflow());}return 0;}

//dinic算法,,,这个算法效率更高,但我还没看懂。。。
 
#include<stdio.h>#include<string.h>#include<algorithm>#include<queue>#include<vector>#define INF 0x3f3f3f3f#define N 110using namespace std;struct zz{int from;int to;int cap;int flow;int next;}edge[N*20];int n,m;int dis[N];int vis[N];int c[N];int head[N],edgenum;void add(int u,int v,int w){zz E={u,v,w,0,head[u]};edge[edgenum]=E;head[u]=edgenum++;zz EE={v,u,0,0,head[v]};edge[edgenum]=EE;head[v]=edgenum++;}bool bfs(int s,int e){int i;memset(dis,-1,sizeof(dis));memset(vis,0,sizeof(vis));queue<int>q;while(!q.empty())q.pop();q.push(s);vis[s]=1;dis[s]=0;while(!q.empty()){int u=q.front();q.pop();for(i=head[u];i!=-1;i=edge[i].next){zz E=edge[i];if(!vis[E.to]&&E.cap>E.flow){vis[E.to]=1;dis[E.to]=dis[u]+1;if(E.to==e)return true;q.push(E.to);}}}return false;}int dfs(int x,int a,int e){if(x==e||a==0)return a;int flow=0,f;for(int &i=c[x];i!=-1;i=edge[i].next){zz& E=edge[i];if(dis[x]+1==dis[E.to]&&(f=dfs(E.to,min(a,E.cap-E.flow),e))>0){E.flow+=f;edge[i^1].flow-=f;flow+=f;a-=f;if(a==0)break;}}return flow;}int maxflow(int s,int e){int flow=0;while(bfs(s,e)){memcpy(c,head,sizeof(head));flow+=dfs(s,INF,e);}return flow;}int main(){int t;int k=1;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);memset(head,-1,sizeof(head));edgenum=0;int u,v,w;while(m--){scanf("%d%d%d",&u,&v,&w);add(u,v,w);}printf("Case %d: %d\n",k++,maxflow(1,n));}return 0;}
//今天又详细理解了一遍dinic算法
#include<stdio.h>#include<string.h>#include<algorithm>#include<queue>#define N 110#define INF 0x3f3f3f3fusing namespace std;int c[N];//保存该节点正在考虑的弧,避免重复计算  int dis[N];//记录该节点到源点的距离 int vis[N];int head[N],edgenum;struct zz{int from;int to;int cup;int flow;int next;}edge[N<<5];void add(int u,int v,int w){zz E={u,v,w,0,head[u]};//正向建边edge[edgenum]=E;head[u]=edgenum++;zz EE={v,u,0,0,head[v]};//反向建 edge[edgenum]=EE;head[v]=edgenum++;}int n,m;bool bfs(int s,int e){memset(dis,-1,sizeof(dis));memset(vis,0,sizeof(vis));queue<int>q;while(!q.empty())//清空队列 q.pop();dis[s]=0;//自己到自己的距离为0vis[s]=1;q.push(s);//进队列while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i!=-1;i=edge[i].next)//遍历 u 所指向的边{zz v=edge[i];if(!vis[v.to]&&v.cup>v.flow){dis[v.to]=dis[u]+1;//建立层次图vis[v.to]=1;//标记if(v.to==e)//找到路径return true;q.push(v.to);}}}return false;//找不到一条可以从源点到汇点的最短路径   }int dfs(int x,int a,int e)//把找到的这个路径上所有的边的当前流量都增加a(a是所找出路径的边中 残余流量的最小值){if(x==e||a==0)return a;int flow=0,f;for(int i=c[x];i!=-1;i=edge[i].next)//从上次考虑的弧开始{zz &E=edge[i];if(dis[E.to]==dis[x]+1&&(f=dfs(E.to,min(a,E.cup-E.flow),e))>0)//可继续增广{E.flow+=f;//正向边  edge[i^1].flow-=f;//反向边flow+=f;//总流量 加上 f a-=f;//最小可增流量 减去f if(a==0)break;}}return flow;}int maxflow(int s,int e){int flow=0;while(bfs(s,e))//存在最短路径{memcpy(c,head,sizeof(head));//功能:由head所指内存区域复制head个字节到c所指内存区域。 //说明:head和c所指内存区域不能重叠,函数返回指向c的指针。flow+=dfs(s,INF,e);}return flow;}int main(){int t;int T=1;int u,v,w;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);edgenum=0;memset(head,-1,sizeof(head));while(m--){scanf("%d%d%d",&u,&v,&w);add(u,v,w);}printf("Case %d: %d\n",T++,maxflow(1,n));}return 0;}


0 0
原创粉丝点击