经典的最大流题POJ1273
来源:互联网 发布:pandorabox域名过滤 编辑:程序博客网 时间:2024/06/07 02:40
百度文库花了5分下的 不过确实是自己需要的东西
经典的最大流题POJ1273
经典的最大流题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
//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]表示。
#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
#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
//#define LOCAL#include <stdio.h>#include <string.h>#include <queue>using namespace std;#define MAXN 210#define INF 0x3f3f3f3fstruct 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 LOCALfreopen("poj1273.txt", "r", stdin);// freopen(".txt", "w", stdout);#endifsolve();return 0;}
SAP实现:poj1273_SAP.cpp
/*
编者感悟:
sap学了很长时间,一直不敢下手写,结果就是不写永远不会真正的理解算法的含义,sap理论很多算法书上都有讲解,但我还是建议看数学专业 图论的书,比如 《有向图的理论,算法及应用》,这本书的内容非常棒,相信看过的都知道吧,比其他算法书上讲的透多了。
SAP有个优化就是 当出现断链时,就可以直接退出,还有个优化是当前弧的优化,这两个优化只需要一句话+一个数组就解决了,相当实惠,好的ISAP执行的效率真的非常高,我写的ISAP用的是链式前向星法表示。
这个就算是模板了吧,虽然写的不是很好。。
*/
#include<iostream>#include<cstdio>#include<memory.h>#include<cmath>using namespace std;#define MAXN 500#define MAXE 40000#define INF 0x7ffffffflong 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) { /* first , check if has augmemt flow */ 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; } /* if .... else ... */ 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;}
- 经典的最大流题POJ1273
- 经典的最大流题POJ1273
- POJ1273 最大流模板题_Edmonds_Karp
- Poj1273最大流 裸题模板
- POJ1273(最大流)
- poj1273 最大流
- 最大流poj1273
- poj1273 最大流
- 最大流poj1273
- 最大流--poj1273
- poj1273 (最大流)
- poj1273(最大流)
- poj1273(最大流)
- POJ1273 最大流水题
- poj1273-----最大流基础(最简单的最大流!--模板题)
- poj1273——最大流
- 网络最大流poj1273,hdoj1532
- POJ1273 Drainage Ditches(最大流)
- VMware网络设置详解 打造超级虚拟网络--全面
- 2012年7月发布的中国企业500强排行榜名单 .
- oracle中查询所有用户表的表名、主键名称、索引、外键等
- java 访问sharepointonline(STS)得到token的方法
- Grails项目示例
- 经典的最大流题POJ1273
- Python正则表达式指南
- oracle 判断为空函数问题null值问题,计算时 null表示无限大
- 如何在非MFC扩展Dll中导出class说明及简单例子
- [乱弹琴]IT人士如何节电
- 怎么获取组件的宽度和高度
- spring 问题
- SSH软件连接 中文乱码
- error:inet_addr() was not declared in this scope