經典的最大流題POJ1273
分類: 網絡流 poj圖論 2012-07-20 11:02 1395人閱讀 評論(1) 收藏 舉報 sap 算法 優化 iostream pair 百度
目錄(?)[+]
百度文庫花了5分下的
不過确實是自己需要的東西
經典的最大流題 POJ1273
——其他練習題 POJ3436 、
題意描述:
現在有m個池塘(從1到m開始編号,1為源點,m為彙點),及n條水渠,給出這n條水渠所連接配接的池塘和所能流過的水量,求水渠中所能流過的水的最大容量.一道基礎的最大流題目。http://poj.org/problem?id=1273
參考資料:
輸入:
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
輸出:
50
程式實作:
增廣路算法Edmonds_Karp
[cpp] view plain copy
- //poj1273_Ek.cpp
- #include<iostream>
- #include<queue>
- using namespace std;
- const int N=201;
- const int INF=99999999;
- int n,m,sum,s,t;//s,t為始點和終點
- int flow[N][N],cap[N][N],a[N],p[N];
- //分别為:flow[u][v]為<u,v>流量、cap[u][v]為<u,v>容量、a[i]表示源點s到節點i的路徑上的最小殘留量、p[i]記錄i的前驅
- int min(int a,int b)
- {
- return a<=b?a:b;
- }
- void Edmonds_Karp()
- {
- int i,u,v;
- queue<int>q;//隊列,用bfs找增廣路
- while(1)
- {
- memset(a,0,sizeof(a));//每找一次,初始化一次
- a[s]=INF;
- q.push(s);//源點入隊
- while(!q.empty())
- {
- u=q.front();
- q.pop();
- for(v=1;v<=m;v++)
- {
- if(!a[v]&&flow[u][v]<cap[u][v])
- {
- p[v]=u;
- q.push(v);
- a[v]=min(a[u],cap[u][v]-flow[u][v]);//s-v路徑上的最小殘量
- }
- }
- }
- if(a[m]==0)//找不到增廣路,則目前流已經是最大流
- break;
- sum+=a[m];//流加上
- for(i=m;i!=s;i=p[i])// //從彙點順着這條增廣路往回走
- {
- flow[p[i]][i]+=a[m];//更新正向流量
- flow[i][p[i]]-=a[m];//更新反向流量
- }
- }
- printf("%d\n",sum);
- }
- int main()
- {
- //freopen("in.txt","r",stdin);
- int v,u,w;
- while(scanf("%d%d",&n,&m)!=EOF)
- {
- s=1;//從1開始
- t=m;//m為彙點
- sum=0;//記錄最大流量
- memset(flow,0,sizeof(flow));//初始化
- memset(cap,0,sizeof(cap));
- while(n--)
- {
- scanf("%d%d%d",&u,&v,&w);
- cap[u][v]+=w;//注意圖中可能出現相同的邊
- }
- Edmonds_Karp();
- }
- return 0;
- }
空間優化: poj1273_Ek_youhua.cpp
在程式實作的時候,我們通常隻是用一個cap數組來記錄容量,而不記錄流量,當流量+1的時候,我們可以通過容量-1來實作,以友善程式的實作。正向用cap[u][v],則反向用cap[v][u]表示。
[cpp] view plain copy
- #include<iostream>
- #include<queue>
- using namespace std;
- const int N=201;
- const int INF=99999999;
- int n,m,sum,s,t,w;//s,t為始點和終點
- int cap[N][N],a[N],p[N];
- int min(int a,int b)
- {
- return a<=b?a:b;
- }
- void Edmonds_Karp()
- {
- int i,u,v;
- queue<int>q;//隊列,用bfs找增廣路
- while(1)
- {
- memset(a,0,sizeof(a));//每找一次,初始化一次
- a[s]=INF;
- q.push(s);//源點入隊
- while(!q.empty())
- {
- u=q.front();
- q.pop();
- for(v=1;v<=m;v++)
- {
- if(!a[v]&&cap[u][v]>0)
- {
- p[v]=u;
- q.push(v);
- a[v]=min(a[u],cap[u][v]);//s-v路徑上的最小殘量
- }
- }
- }
- if(a[m]==0)//找不到增廣路,則目前流已經是最大流
- break;
- sum+=a[m];//流加上
- for(i=m;i!=s;i=p[i])// //從彙點順着這條增廣路往回走
- {
- cap[p[i]][i]-=a[m];//更新正向流量
- cap[i][p[i]]+=a[m];//更新反向流量
- }
- }
- printf("%d\n",sum);
- }
- int main()
- {
- // freopen("in.txt","r",stdin);
- int v,u;
- while(scanf("%d%d",&n,&m)!=EOF)
- {
- s=1;//從1開始
- t=m;//m為彙點
- sum=0;//記錄最大流量
- memset(cap,0,sizeof(cap));//初始化
- while(n--)
- {
- scanf("%d%d%d",&u,&v,&w);
- cap[u][v]+=w;//注意圖中可能出現相同的邊
- }
- Edmonds_Karp();
- }
- return 0;
- }
Dinic鄰接矩陣實作:poj1273_Dinic.cpp
[cpp] view plain copy
- #include <cstdio>
- #include <cstring>
- #include <cstdlib>
- #include <iostream>
- #define min(x,y) ((x<y)?(x):(y))
- using namespace std;
- const int MAX=0x5fffffff;//
- int tab[250][250];//鄰接矩陣
- int dis[250];//距源點距離,分層圖
- int q[2000],h,r;//BFS隊列 ,首,尾
- int N,M,ANS;//N:點數;M,邊數
- int BFS()
- { int i,j;
- memset(dis,0xff,sizeof(dis));//以-1填充
- dis[1]=0;
- h=0;r=1;
- q[1]=1;
- while (h<r)
- {
- j=q[++h];
- for (i=1;i<=N;i++)
- if (dis[i]<0 && tab[j][i]>0)
- {
- dis[i]=dis[j]+1;
- q[++r]=i;
- }
- }
- if (dis[N]>0)
- return 1;
- else
- return 0;//彙點的DIS小于零,表明BFS不到彙點
- }
- //Find代表一次增廣,函數傳回本次增廣的流量,傳回0表示無法增廣
- int find(int x,int low)//Low是源點到現在最窄的(剩餘流量最小)的邊的剩餘流量
- {
- int i,a=0;
- if (x==N)return low;//是彙點
- for (i=1;i<=N;i++)
- if (tab[x][i] >0 //聯通
- && dis[i]==dis[x]+1 //是分層圖的下一層
- &&(a=find(i,min(low,tab[x][i]))))//能到彙點(a <> 0)
- {
- tab[x][i]-=a;
- tab[i][x]+=a;
- return a;
- }
- return 0;
- }
- int main()
- {
- //freopen("ditch.in" ,"r",stdin );
- //freopen("ditch.out","w",stdout);
- int i,j,f,t,flow,tans;
- while (scanf("%d%d",&M,&N)!=EOF){
- memset(tab,0,sizeof(tab));
- for (i=1;i<=M;i++)
- {
- scanf("%d%d%d",&f,&t,&flow);
- tab[f][t]+=flow;
- }
- //
- ANS=0;
- while (BFS())//要不停地建立分層圖,如果BFS不到彙點才結束
- {
- while(tans=find(1,0x7fffffff))ANS+=tans;//一次BFS要不停地找增廣路,直到找不到為止
- }
- printf("%d\n",ANS);
- }
- //system("pause");
- }
Dinic鄰接表實作:poj1273_dinic.cpp
[cpp] view plain copy
- //#define LOCAL
- #include <stdio.h>
- #include <string.h>
- #include <queue>
- using namespace std;
- #define MAXN 210
- #define INF 0x3f3f3f3f
- struct Edge
- {
- int st, ed;
- int c;
- int next;
- }edge[MAXN << 1];
- int n, m;
- int s, t;
- int ans;
- int e = 0;
- int head[MAXN];
- int d[MAXN];
- int min(int a, int b)
- {
- return a < b ? a : b;
- }
- void init()
- {
- int i, j;
- int a, b, c;
- s = 1;
- t = m;
- e = 0;
- ans = 0;
- memset(head, -1, sizeof(head));
- for(i = 1; i <= n; i++)
- {
- scanf("%d%d%d", &a, &b, &c);
- edge[e].st = a;
- edge[e].ed = b;
- edge[e].c = c;
- edge[e].next = head[a];
- head[a]= e++;
- edge[e].st = b;
- edge[e].ed = a;
- edge[e].next = head[b];
- head[b] = e++;
- }
- }
- int bfs()
- {
- memset(d, -1, sizeof(d));
- queue<int> q;
- d[s] = 0;
- q.push(s);
- int i;
- int cur;
- while(!q.empty())
- {
- cur = q.front();
- q.pop();
- for(i = head[cur]; i != -1; i = edge[i].next)
- {
- if(d[edge[i].ed] == -1 && edge[i].c > 0)
- {
- d[edge[i].ed] = d[cur] + 1;
- q.push(edge[i].ed);
- }
- }
- }
- if(d[t] < 0)
- return 0;
- return 1;
- }
- int dinic(int x, int flow)
- {
- if(x == t)
- return flow;
- int i, a;
- for(i = head[x]; i != -1; i = edge[i].next)
- {
- if(d[edge[i].ed] == d[x] + 1 && edge[i].c > 0 && (a = dinic(edge[i].ed, min(flow, edge[i].c))))
- {
- edge[i].c -= a;
- edge[i ^ 1].c += a;
- return a;
- }
- }
- return 0;
- }
- void solve()
- {
- while(scanf("%d%d", &n, &m) != EOF)
- {
- init();
- while(bfs())
- {
- int increment;
- increment = dinic(1, INF);
- ans += increment;
- }
- printf("%d\n", ans);
- }
- }
- int main()
- {
- #ifdef LOCAL
- freopen("poj1273.txt", "r", stdin);
- // freopen(".txt", "w", stdout);
- #endif
- solve();
- return 0;
- }
SAP實作:poj1273_SAP.cpp
[cpp] view plain copy
- #include<iostream>
- #include<cstdio>
- #include<memory.h>
- #include<cmath>
- using namespace std;
- #define MAXN 500
- #define MAXE 40000
- #define INF 0x7fffffff
- long ne,nv,tmp,s,t,index;
- struct Edge{
- long next,pair;
- long v,cap,flow;
- }edge[MAXE];
- long net[MAXN];
- long ISAP()
- {
- long numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN];
- long cur_flow,max_flow,u,tmp,neck,i;
- memset(dist,0,sizeof(dist));
- memset(numb,0,sizeof(numb));
- memset(pre,-1,sizeof(pre));
- for(i = 1 ; i <= nv ; ++i)
- curedge[i] = net[i];
- numb[nv] = nv;
- max_flow = 0;
- u = s;
- while(dist[s] < nv)
- {
- if(u == t)
- {
- cur_flow = INF;
- for(i = s; i != t;i = edge[curedge[i]].v)
- {
- if(cur_flow > edge[curedge[i]].cap)
- {
- neck = i;
- cur_flow = edge[curedge[i]].cap;
- }
- }
- for(i = s; i != t; i = edge[curedge[i]].v)
- {
- tmp = curedge[i];
- edge[tmp].cap -= cur_flow;
- edge[tmp].flow += cur_flow;
- tmp = edge[tmp].pair;
- edge[tmp].cap += cur_flow;
- edge[tmp].flow -= cur_flow;
- }
- max_flow += cur_flow;
- u = neck;
- }
- for(i = curedge[u]; i != -1; i = edge[i].next)
- if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1)
- break;
- if(i != -1)
- {
- curedge[u] = i;
- pre[edge[i].v] = u;
- u = edge[i].v;
- }else{
- if(0 == --numb[dist[u]]) break;
- curedge[u] = net[u];
- for(tmp = nv,i = net[u]; i != -1; i = edge[i].next)
- if(edge[i].cap > 0)
- tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v];
- dist[u] = tmp + 1;
- ++numb[dist[u]];
- if(u != s) u = pre[u];
- }
- }
- return max_flow;
- }
- int main() {
- long i,j,np,nc,m,n;
- long a,b,val;
- long g[MAXN][MAXN];
- while(scanf("%d%d",&ne,&nv)!=EOF)
- {
- s = 1;
- t = nv;
- memset(g,0,sizeof(g));
- memset(net,-1,sizeof(net));
- for(i=0;i<ne;++i)
- {
- scanf("%ld%ld%ld",&a,&b,&val);
- g[a][b] += val;
- }
- for(i=1;i<=nv;++i)
- for(j = i; j <= nv;++j)
- if(g[i][j]||g[j][i])
- {
- edge[index].next = net[i];
- edge[index].v = j;
- edge[index].cap = g[i][j];
- edge[index].flow = 0;
- edge[index].pair = index+1;
- net[i] = index++;
- edge[index].next = net[j];
- edge[index].v = i;
- edge[index].cap = g[j][i];
- edge[index].flow = 0;
- edge[index].pair = index-1;
- net[j] = index++;
- }
- printf("%ld\n",ISAP());
- }
- return 0;
- }