[转载 ]POJ 1273 最大流模板

转载

百度文库花了5分下的[转载 ]POJ 1273 最大流模板 不过确实是自己需要的东西[转载 ]POJ 1273 最大流模板
经典的最大流题POJ1273

——其他练习题 POJ3436 、

题意描述:

现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条水渠,给出这n条水渠所连接的池塘和所能流过的水量,求水渠中所能流过的水的最大容量.一道基础的最大流题目。但是模板小心使用,目前只是求单源点的最大流。

参考数据:

输入:

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=;
const int INF=;
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()
{
memset(a,,sizeof(a));//每找一次,初始化一次
a[s]=INF;
q.push(s);//源点入队
while(!q.empty())
{
u=q.front();
q.pop();
for(v=;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]==)//找不到增广路,则当前流已经是最大流
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开始
t=m;//m为汇点
sum=;//记录最大流量
memset(flow,,sizeof(flow));//初始化
memset(cap,,sizeof(cap));
while(n--)
{
scanf("%d%d%d",&u,&v,&w);
cap[u][v]+=w;//注意图中可能出现相同的边
}
Edmonds_Karp();
}
return ;
}

空间优化:

在程序实现的时候,我们通常只是用一个cap数组来记录容量,而不记录流量,当流量+1的时候,我们可以通过容量-1来实现,以方便程序的实现。正向用cap[u][v],则反向用cap[v][u]表示。

 #include<iostream>
#include<queue>
using namespace std;
const int N=;
const int INF=;
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()
{
memset(a,,sizeof(a));//每找一次,初始化一次
a[s]=INF;
q.push(s);//源点入队
while(!q.empty())
{
u=q.front();
q.pop();
for(v=;v<=m;v++)
{
if(!a[v]&&cap[u][v]>)
{
p[v]=u;
q.push(v);
a[v]=min(a[u],cap[u][v]);//s-v路径上的最小残量
}
}
}
if(a[m]==)//找不到增广路,则当前流已经是最大流
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开始
t=m;//m为汇点
sum=;//记录最大流量
memset(cap,,sizeof(cap));//初始化
while(n--)
{
scanf("%d%d%d",&u,&v,&w);
cap[u][v]+=w;//注意图中可能出现相同的边
}
Edmonds_Karp();
}
return ;
}

Dinic邻接矩阵实现

 #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[][];//邻接矩阵
int dis[];//距源点距离,分层图
int q[],h,r;//BFS队列 ,首,尾
int N,M,ANS;//N:点数;M,边数
int BFS()
{ int i,j;
memset(dis,0xff,sizeof(dis));//以-1填充
dis[]=;
h=;r=;
q[]=;
while (h<r)
{
j=q[++h];
for (i=;i<=N;i++)
if (dis[i]< && tab[j][i]>)
{
dis[i]=dis[j]+;
q[++r]=i;
}
}
if (dis[N]>)
return ;
else
return ;//汇点的DIS小于零,表明BFS不到汇点
}
//Find代表一次增广,函数返回本次增广的流量,返回0表示无法增广
int find(int x,int low)//Low是源点到现在最窄的(剩余流量最小)的边的剩余流量
{
int i,a=;
if (x==N)return low;//是汇点
for (i=;i<=N;i++)
if (tab[x][i] > //联通
&& dis[i]==dis[x]+ //是分层图的下一层
&&(a=find(i,min(low,tab[x][i]))))//能到汇点(a <> 0)
{
tab[x][i]-=a;
tab[i][x]+=a;
return a;
}
return ;
}
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,,sizeof(tab));
for (i=;i<=M;i++)
{
scanf("%d%d%d",&f,&t,&flow);
tab[f][t]+=flow;
}
//
ANS=;
while (BFS())//要不停地建立分层图,如果BFS不到汇点才结束
{
while(tans=find(,0x7fffffff))ANS+=tans;//一次BFS要不停地找增广路,直到找不到为止
}
printf("%d\n",ANS);
}
//system("pause");
}

Dinic邻接表实现

 //#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 << ]; int n, m;
int s, t;
int ans;
int e = ;
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 = ;
t = m;
e = ;
ans = ;
memset(head, -, sizeof(head));
for(i = ; 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, -, sizeof(d));
queue<int> q;
d[s] = ;
q.push(s);
int i;
int cur;
while(!q.empty())
{
cur = q.front();
q.pop();
for(i = head[cur]; i != -; i = edge[i].next)
{
if(d[edge[i].ed] == - && edge[i].c > )
{
d[edge[i].ed] = d[cur] + ;
q.push(edge[i].ed);
}
}
}
if(d[t] < )
return ;
return ;
} int dinic(int x, int flow)
{
if(x == t)
return flow;
int i, a;
for(i = head[x]; i != -; i = edge[i].next)
{
if(d[edge[i].ed] == d[x] + && edge[i].c > && (a = dinic(edge[i].ed, min(flow, edge[i].c))))
{
edge[i].c -= a;
edge[i ^ ].c += a;
return a;
}
}
return ;
} void solve()
{
while(scanf("%d%d", &n, &m) != EOF)
{
init();
while(bfs())
{
int increment;
increment = dinic(, INF);
ans += increment;
}
printf("%d\n", ans);
}
} int main()
{
#ifdef LOCAL
freopen("poj1273.txt", "r", stdin);
// freopen(".txt", "w", stdout);
#endif
solve();
return ;
}

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 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,,sizeof(dist));
memset(numb,,sizeof(numb));
memset(pre,-,sizeof(pre));
for(i = ; i <= nv ; ++i)
curedge[i] = net[i];
numb[nv] = nv;
max_flow = ;
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 != -; i = edge[i].next)
if(edge[i].cap > && dist[u] == dist[edge[i].v]+)
break;
if(i != -)
{
curedge[u] = i;
pre[edge[i].v] = u;
u = edge[i].v;
}else{
if( == --numb[dist[u]]) break;
curedge[u] = net[u];
for(tmp = nv,i = net[u]; i != -; i = edge[i].next)
if(edge[i].cap > )
tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v];
dist[u] = tmp + ;
++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 = ;
t = nv;
memset(g,,sizeof(g));
memset(net,-,sizeof(net));
for(i=;i<ne;++i)
{
scanf("%ld%ld%ld",&a,&b,&val);
g[a][b] += val;
}
for(i=;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 = ;
edge[index].pair = index+;
net[i] = index++;
edge[index].next = net[j];
edge[index].v = i;
edge[index].cap = g[j][i];
edge[index].flow = ;
edge[index].pair = index-;
net[j] = index++;
}
printf("%ld\n",ISAP());
}
return ;
}
上一篇:怎样查询锁表的SQL


下一篇:写vue项目时候 零星的笔记