标签:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 58538 | Accepted: 22485 |
Description
Input
Output
Sample Input
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
Sample Output
50题意:有n条路,m个点,让你求出以1为源点,m为汇点的最大流;
ISAP()
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> #include <iostream> #include <queue> #include <set> using namespace std; const int inf=0x3f3f3f3f; //head存储前向星的有相同起点的弧,num存储各层剩余节点数目,d存储各节点的层数,cur存储当前弧,pre存储路径,即当前节点的上一个节点,用于回溯。 int head[1010],num[1010],d[1010],cur[1010],n,m,cnt,s,t,q[100010],nv,pre[1010]; int maxint=inf; struct node { int v,cap; int next; }edge[10010]; void add(int u,int v,int cap) { //加正向弧 edge[cnt].v=v; edge[cnt].cap=cap; edge[cnt].next=head[u]; head[u]=cnt++; //加反向弧 edge[cnt].v=u; edge[cnt].cap=0; edge[cnt].next=head[v]; head[v]=cnt++; } void bfs()//用bfs对每个节点进行分层 { //算法执行之前需要用 BFS 初始化 d 数组,方法是从 t 到 s 逆向进行 int i,j; memset(num,0,sizeof(num)); memset(d,-1,sizeof(d)); int f1=0,f2=0; q[f1++]=t;//从 d[t]=0; num[0]=1; while(f2<=f1){ int u=q[f2++]; for(i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(d[v]!=-1) continue; d[v]=d[u]+1;//此节点的层数是上一节点的下一层 num[d[v]]++;//该层数的节点数+1 q[f1++]=v; } } } void isap() { memcpy(cur,head,sizeof(cur)); bfs(); int flow=0,u=pre[s]=s,i; while(d[s]<nv){//如果d[s]大于nv,说明有断层 if(u==t){ int f=maxint,pos; for(i=s;i!=t;i=edge[cur[i]].v){//找该路上的最少残余流量 if(f>edge[cur[i]].cap){ f=edge[cur[i]].cap; pos=i; } } for(i=s;i!=t;i=edge[cur[i]].v){//更新,将该路上的所有流量-最少参与流量 edge[cur[i]].cap-=f; edge[cur[i]^1].cap+=f; } flow+=f;//加入总流量 u=pos; } for(i=cur[u];i!=-1;i=edge[i].next){ if(d[edge[i].v]+1==d[u]&&edge[i].cap){ break; } } if(i!=-1){//如果找到可行增广路,更新 cur[u]=i;//更新当前弧 pre[edge[i].v]=u;//更新路径 u=edge[i].v;//回溯 } else{ if(--num[d[u]]==0) break;//gap优化 int mind=nv; for(i=head[u];i!=-1;i=edge[i].next){//找最小层次 if(edge[i].cap&&mind>d[edge[i].v]){ cur[u]=i; mind=d[edge[i].v]; } } d[u]=mind+1; num[d[u]]++; u=pre[u]; } } printf("%d\n",flow); } int main() { int i,a,b,c; while(~scanf("%d %d",&n,&m)){ memset(head,-1,sizeof(head)); cnt=0; while(n--){ scanf("%d %d %d",&a,&b,&c);//加边 add(a,b,c); } s=1; t=m; nv=t+1; isap(); } return 0; }
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> #include <queue> using namespace std; #define inf 9999999999 int flow[210][210]; int maxflow[210],father[210],vis[210]; int max_flow; int m,i; void EK(int s,int e) { queue<int >q; int u,v; while(1) { memset(maxflow,0,sizeof(maxflow));//每次寻找增广路径都将每个点的流入容量置为0; memset(vis,0,sizeof(vis)); maxflow[s]=inf;//源点的流入量置为正无穷; q.push(s);//将源点压入队列; while(!q.empty())//当队列不为空 { u=q.front(); q.pop(); for(v=s;v<=e;v++) { if(!vis[v]&&flow[u][v]>0) { vis[v]=1; father[v]=u;//记录下他的父亲方便反向更新 q.push(v); maxflow[v]=min(maxflow[u],flow[u][v]);//当前点的容量为父亲点容量与边流量的较小者 } } if(maxflow[e]>0)//如果找到了汇点并且汇点容量不为0则清空队列 { while(!q.empty()) q.pop(); break; } } if(maxflow[e]==0)//已经找不到到汇点的增光路经了,就退出整个循环 break; for(i=e;i!=s;i=father[i]) { flow[father[i]][i]-=maxflow[e];//正向更新 flow[i][father[i]]+=maxflow[e];//反向更新 } max_flow+=maxflow[e];//更新最大流 } } int main() { int n; int si,ei,ci; while(~scanf("%d %d",&n,&m)) { max_flow=0;//最大流初始化; memset(flow,0,sizeof(flow)); for(i=0;i<n;i++) { scanf("%d %d %d",&si,&ei,&ci); flow[si][ei]+=ci; } EK(1,m); printf("%d\n",max_flow); } }
POJ 1273-Drainage Ditches(网络流_最大流_ISAP()算法和EK()算法)
标签:
原文地址:http://blog.csdn.net/u013486414/article/details/42834695