| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 58538 | Accepted: 22485 |
Description
Input
Output
Sample Input
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
Sample Output
50题意:有n条路,m个点,让你求出以1为源点,m为汇点的最大流;
ISAP()
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <set>
using namespace std;
const int inf=0x3f3f3f3f;
//head存储前向星的有相同起点的弧,num存储各层剩余节点数目,d存储各节点的层数,cur存储当前弧,pre存储路径,即当前节点的上一个节点,用于回溯。
int head[1010],num[1010],d[1010],cur[1010],n,m,cnt,s,t,q[100010],nv,pre[1010];
int maxint=inf;
struct node
{
int v,cap;
int next;
}edge[10010];
void add(int u,int v,int cap)
{
//加正向弧
edge[cnt].v=v;
edge[cnt].cap=cap;
edge[cnt].next=head[u];
head[u]=cnt++;
//加反向弧
edge[cnt].v=u;
edge[cnt].cap=0;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void bfs()//用bfs对每个节点进行分层
{
//算法执行之前需要用 BFS 初始化 d 数组,方法是从 t 到 s 逆向进行
int i,j;
memset(num,0,sizeof(num));
memset(d,-1,sizeof(d));
int f1=0,f2=0;
q[f1++]=t;//从
d[t]=0;
num[0]=1;
while(f2<=f1){
int u=q[f2++];
for(i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(d[v]!=-1) continue;
d[v]=d[u]+1;//此节点的层数是上一节点的下一层
num[d[v]]++;//该层数的节点数+1
q[f1++]=v;
}
}
}
void isap()
{
memcpy(cur,head,sizeof(cur));
bfs();
int flow=0,u=pre[s]=s,i;
while(d[s]<nv){//如果d[s]大于nv,说明有断层
if(u==t){
int f=maxint,pos;
for(i=s;i!=t;i=edge[cur[i]].v){//找该路上的最少残余流量
if(f>edge[cur[i]].cap){
f=edge[cur[i]].cap;
pos=i;
}
}
for(i=s;i!=t;i=edge[cur[i]].v){//更新,将该路上的所有流量-最少参与流量
edge[cur[i]].cap-=f;
edge[cur[i]^1].cap+=f;
}
flow+=f;//加入总流量
u=pos;
}
for(i=cur[u];i!=-1;i=edge[i].next){
if(d[edge[i].v]+1==d[u]&&edge[i].cap){
break;
}
}
if(i!=-1){//如果找到可行增广路,更新
cur[u]=i;//更新当前弧
pre[edge[i].v]=u;//更新路径
u=edge[i].v;//回溯
}
else{
if(--num[d[u]]==0) break;//gap优化
int mind=nv;
for(i=head[u];i!=-1;i=edge[i].next){//找最小层次
if(edge[i].cap&&mind>d[edge[i].v]){
cur[u]=i;
mind=d[edge[i].v];
}
}
d[u]=mind+1;
num[d[u]]++;
u=pre[u];
}
}
printf("%d\n",flow);
}
int main()
{
int i,a,b,c;
while(~scanf("%d %d",&n,&m)){
memset(head,-1,sizeof(head));
cnt=0;
while(n--){
scanf("%d %d %d",&a,&b,&c);//加边
add(a,b,c);
}
s=1;
t=m;
nv=t+1;
isap();
}
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <queue>
using namespace std;
#define inf 9999999999
int flow[210][210];
int maxflow[210],father[210],vis[210];
int max_flow;
int m,i;
void EK(int s,int e)
{
queue<int >q;
int u,v;
while(1)
{
memset(maxflow,0,sizeof(maxflow));//每次寻找增广路径都将每个点的流入容量置为0;
memset(vis,0,sizeof(vis));
maxflow[s]=inf;//源点的流入量置为正无穷;
q.push(s);//将源点压入队列;
while(!q.empty())//当队列不为空
{
u=q.front();
q.pop();
for(v=s;v<=e;v++)
{
if(!vis[v]&&flow[u][v]>0)
{
vis[v]=1;
father[v]=u;//记录下他的父亲方便反向更新
q.push(v);
maxflow[v]=min(maxflow[u],flow[u][v]);//当前点的容量为父亲点容量与边流量的较小者
}
}
if(maxflow[e]>0)//如果找到了汇点并且汇点容量不为0则清空队列
{
while(!q.empty())
q.pop();
break;
}
}
if(maxflow[e]==0)//已经找不到到汇点的增光路经了,就退出整个循环
break;
for(i=e;i!=s;i=father[i])
{
flow[father[i]][i]-=maxflow[e];//正向更新
flow[i][father[i]]+=maxflow[e];//反向更新
}
max_flow+=maxflow[e];//更新最大流
}
}
int main()
{
int n;
int si,ei,ci;
while(~scanf("%d %d",&n,&m))
{
max_flow=0;//最大流初始化;
memset(flow,0,sizeof(flow));
for(i=0;i<n;i++)
{
scanf("%d %d %d",&si,&ei,&ci);
flow[si][ei]+=ci;
}
EK(1,m);
printf("%d\n",max_flow);
}
}
POJ 1273-Drainage Ditches(网络流_最大流_ISAP()算法和EK()算法)
原文:http://blog.csdn.net/u013486414/article/details/42834695