经典的最大流题POJ1273

来源:互联网 发布:pandorabox域名过滤 编辑:程序博客网 时间:2024/06/07 02:40

百度文库花了5分下的可怜 不过确实是自己需要的东西吐舌头
经典的最大流题POJ1273

——其他练习题 POJ3436 

题意描述:

现在有m个池塘(1m开始编号,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;}


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 善领wifi连上网不能用怎么办 苹果手机软件更新后网速太慢怎么办 装了固态硬盘开机还慢怎么办 华为荣耀8青春版玩游戏卡怎么办 光猫自带wifi网络很差怎么办 侠盗猎车手自由城之章卡退怎么办? 夏天带头盔晃眼睛太厉害怎么办 别人把钱误转我卡上我怎么办? 家里预留的的网线太短怎么办 电信路由器坏了网线接口断了怎么办 数据线充手机的接头处断了怎么办 新买的小米手环充不进去电怎么办 绝地求生手游被队友故意炸死怎么办 一加3t屏幕开了怎么办? 孕妇吃了8个杏怎么办啊 洗碗盆落水器垫子密封不好怎么办? 手剥橙子剥的特别疼怎么办? 经常带对讲机的耳麦耳朵痛怎么办 公安检查遇到穿便装的军人怎么办 cf幽灵鬼呼吸辅军训刘海怎么办助 眼睛被等离子切割器的光烤了怎么办 玩王者的时候屏幕竖着了该怎么办 铝合金门双包门套比墙的厚了怎么办 磁共振检查后发现带金属了怎么办 贴了乳贴过免痒怎么办 yy别人听见我打游戏的声音怎么办 微信的聊天记录发错邮箱怎么办 百度云盘文件有违规内容怎么办 天籁一键启动钥匙没电怎么办 中兴手机系统界面已停止运行怎么办 怎么办可以复制成不关联的文档 希捷400g硬盘电机不转怎么办 金立手机微信语音播放失败怎么办 手机4g网络变2g怎么办 生存战争2吃了腐烂的食物后怎么办 古筝调音 d的显示为b怎么办 消防建审没有原有的结构图纸怎么办 生石灰弄到脸上用水洗后发热怎么办 吃了没熟的鹅肝怎么办 蹲式厕所被袜子堵了怎么办 自热包的水喝了怎么办