hdu1532 &pku1273 Drainage Ditches(最大流EK算法)
本题的算法流程
1.初始化pre
2.BFS求增广路径P
不存在:break ,return flow;
3.求P中最小值aug
4.修改P中残留容量,流flow++++
需要注意:
1°BFS找增广路径
2°前缀数组pre的遍历
//pku1273 hdu1532
#include<stdio.h>
#include<string.h>
#define V 300
#define INF 100000000
int n, m; //分别表示图的边数n 和 顶点数m
int c[V][V]; //记录残留容量
int EK( int s, int t ) //输入源点s和汇点t
{
int queue[V],pre[V],u,v,p,q,aug;
int flow=0;
while(1)
{
memset(pre,-1,sizeof(pre)); //清空上一次的增广路径,用于记录父节点
for(queue[p=q=0]=s;p<=q;p++) //广度优先搜索
{
u=queue[p];
for(v=0;v<m&&pre[t]<0;v++) //可优化?
if(c[u][v]>0&&pre[v]<0)
{
pre[v]=u;
queue[++q]=v; //队列上限增加
}
if(pre[t]>=0) //找到了汇点的前导(增广路)
break; //for的退出点
}
if(pre[t]<0) break; //找不到汇点的前导,不存在增广路
//while的退出点
aug=INF; //记录最小残留容量
for(u=pre[v=t];v!=s;v=u,u=pre[u]) //在增广路中找最小值
if(aug>c[u][v])
aug=c[u][v];
for(u=pre[v=t];v!=s;v=u,u=pre[u])
{
c[u][v]-=aug; //残留容量----
c[v][u]+=aug; //反对称性++++
}
flow+=aug; //流++++++
}
return flow;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int x,y,cost;
memset(c,0,sizeof(c));
for(int i=0;i<n;i++)
{ scanf("%d%d%d",&x,&y,&cost);
c[x-1][y-1]+=cost;
}
printf("%d\n",EK(0,m-1));
}
return 0;
}
小小优化之后
//pku1273 hdu1532
#include<stdio.h>
#include<string.h>
#define V 201
#define INF 2000000000
int c[V][V],n,m;
int EK(int s,int t)
{
int i,j,u,v,aug,flow,queue[V],p,q,pre[V];
flow=0;
while(1)
{
memset(pre,0,sizeof(pre));
for(queue[p=q=1]=s;p<=q;p++)
{
u=queue[p];
for(v=1;v<=m&&pre[t]==0;v++)
if(c[u][v]>0&&pre[v]==0)
{
pre[v]=u;
queue[++q]=v;
}
}
if(pre[t]==0) break;
aug=INF;
for(v=t;v!=s;v=pre[v])
if(aug>c[pre[v]][v]) aug=c[pre[v]][v];
flow+=aug;
for(v=t;v!=s;v=pre[v])
{
c[pre[v]][v]-=aug;
//c[v][pre[v]]+=aug; //不是双向边的话 这行没有意义
}
}
return flow;
}
main()
{
int s,e,cost,i;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(c,0,sizeof(c));
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&s,&e,&cost);
c[s][e]+=cost;
}
printf("%d\n",EK(1,m));
}
}