5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
50
题大意:给出边数N,点数M,每条边都是单向的,问从1点到M的最大流是多少。
方法一:ISAP
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define captype __int64
const int MAXN = 100010;
const int MAXM = 400010;
const int INF = 1<<30;
struct EDG{
int to,next;
captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN]; //每种距离(或可认为是高度)点的个数
int dis[MAXN]; //每个点到终点eNode 的最短距离
int cur[MAXN]; //cur[u] 表示从u点出发可流经 cur[u] 号边
void init(){
eid=0;
memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
edg[eid].to=v; edg[eid].next=head[u];
edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;
edg[eid].to=u; edg[eid].next=head[v];
edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
//预处理eNode点到所有点的最短距离
void BFS(int sNode, int eNode){
queue<int>q;
memset(gap,0,sizeof(gap));
memset(dis,-1,sizeof(dis));
gap[0]=1;
dis[eNode]=0;
q.push(eNode);
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=head[u]; i!=-1; i=edg[i].next){
int v=edg[i].to;
if(dis[v]==-1){
dis[v]=dis[u]+1;
gap[dis[v]]++;
q.push(v);
}
}
}
}
int S[MAXN]; //路径栈,存的是边的id号
captype maxFlow_sap(int sNode,int eNode, int n){
BFS(sNode, eNode); //预处理eNode到所有点的最短距离
if(dis[sNode]==-1) return 0; //源点到不可到达汇点
memcpy(cur,head,sizeof(head));
int top=0; //栈顶
captype ans=0; //最大流
int u=sNode;
while(dis[sNode]<n){ //判断从sNode点有没有流向下一个相邻的点
if(u==eNode){ //找到一条可增流的路
captype Min=INF ;
int inser;
for(int i=0; i<top; i++) //从这条可增流的路找到最多可增的流量Min
if(Min>edg[S[i]].cap-edg[S[i]].flow){
Min=edg[S[i]].cap-edg[S[i]].flow;
inser=i;
}
for(int i=0; i<top; i++){
edg[S[i]].flow+=Min;
edg[S[i]^1].flow-=Min; //可回流的边的流量
}
ans+=Min;
top=inser; //从这条可增流的路中的流量瓶颈 边的上一条边那里是可以再增流的,所以只从断流量瓶颈 边裁断
u=edg[S[top]^1].to; //流量瓶颈 边的起始点
continue;
}
bool flag = false; //判断能否从u点出发可往相邻点流
int v;
for(int i=cur[u]; i!=-1; i=edg[i].next){
v=edg[i].to;
if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
flag=true;
cur[u]=i;
break;
}
}
if(flag){
S[top++] = cur[u]; //加入一条边
u=v;
continue;
}
//如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
int Mind= n;
for(int i=head[u]; i!=-1; i=edg[i].next){
if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
Mind=dis[edg[i].to];
cur[u]=i;
}}
gap[dis[u]]--;
if(gap[dis[u]]==0) return ans; //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
//因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
dis[u]=Mind+1; //如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
gap[dis[u]]++;
if(u!=sNode) u=edg[S[--top]^1].to; //退一条边
}
return ans;
}
int main(){
int n,m,u,v;
captype c;
while(scanf("%d%d",&m,&n)>0){
init();
while(m--){
scanf("%d%d%I64d",&u,&v,&c);
addEdg(u,v,c);
}
printf("%I64d\n",maxFlow_sap(1,n,n));
}
}
方法二:压入重标记push_relabel
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define captype __int64
const int N = 210;
const int MAX= 1<<30;
struct EDG{
int to,nxt;
captype c; //每条边的残留量
}edg[N*N];
int head[N],eid;
captype vf[N]; //顶点的剩余流量
int h[N]; //顶点的高度
//int n; //顶点个总个数,包含源点与汇点
int min(int a,int b){return a>b?b:a; }
void init(){
memset(head,-1,sizeof(head));
eid=0;
}
//添加 有向边
void addEdg(int u , int v, captype c){
edg[eid].to=v; edg[eid].nxt=head[u]; edg[eid].c=c; head[u]=eid++;
edg[eid].to=u; edg[eid].nxt=head[v]; edg[eid].c=0; head[v]=eid++;
}
captype maxFlow(int sNode,int eNode,int n){//源点与汇点
captype minh,ans=0;
queue<int>q;
memset(h,0,sizeof(h));
memset(vf,0,sizeof(vf));
h[sNode]=n+1; //源点的高度
vf[sNode]=MAX; //源点的余流
q.push(sNode);
while(!q.empty()){
int u=q.front(); q.pop();
minh=MAX;
for(int i=head[u]; i!=-1; i=edg[i].nxt){
int v=edg[i].to;
captype fp;
if(edg[i].c<vf[u])fp=edg[i].c;
else fp=vf[u];
if(fp>0 ){
minh=min(minh, h[v]);
if(u==sNode || h[u]==h[v]+1){
edg[i].c-=fp;
edg[i^1].c+=fp; //反向边,给个反回的通道
vf[u]-=fp;
vf[v]+=fp;
if(v==eNode) ans+=fp; //当到达汇点时,就加入最大流中
if(v!=sNode && v!=eNode ) //只有即不是源点,也不是汇点时才能进队列
q.push(v);
}
}
if(vf[u]==0) break; //如果顶点的余流为0,则可以跳出for循环
}
//如果不是源点(也非汇点),且顶点仍有余流,则重新标记 高度+1 入队
//这里赋值为最低的相邻顶点的高度高一个单位,也可以简单的在原高度+1
if(u!=sNode && vf[u]>0){
h[u] = minh + 1;
q.push(u);
}
}
return ans;
}
int main(){
int n,m,u,v;
captype c;
while(scanf("%d%d",&m,&n)>0){
init();
while(m--){
scanf("%d%d%I64d",&u,&v,&c);
addEdg(u,v,c);
}
printf("%I64d\n",maxFlow(1,n,n));
}
}
方法三:EK#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define captype __int64
const int N = 205;
captype cap[N][N],f[N][N],rest[N];
int sNode,eNode,pre[N];
void init(){
memset(f,0,sizeof(f));
memset(cap,0,sizeof(cap));
}
bool searchPath(int n){//找一条增广路
bool vist[N]={0};
queue<int>q;
int u,v;
u=sNode; vist[u]=1;
pre[u]=u; rest[u]=1<<30;
q.push(u);
while(!q.empty()){
u=q.front(); q.pop();
for(v=1; v<=n; v++)
if(!vist[v]&&cap[u][v]-f[u][v]>0)
{
vist[v]=1; pre[v]=u;
if(cap[u][v]-f[u][v]>rest[u])
rest[v]=rest[u];
else
rest[v]=cap[u][v]-f[u][v];
if(v==eNode) return true;
q.push(v);
}
}
return false;
}
captype maxflow(int s,int t,int n){
captype ans=0;
sNode=s; eNode=t;
while(searchPath(n)){
ans+=rest[eNode];
int v=eNode;
while(v!=sNode){
int u=pre[v];
f[u][v]+=rest[eNode];
f[v][u]-=rest[eNode];//给一个回流的机会
v=u;
}
}
return ans;
}
int main(){
int n,m,u,v;
captype c;
while(scanf("%d%d",&m,&n)>0){
init();
while(m--){
scanf("%d%d%I64d",&u,&v,&c);
cap[u][v]+=c;
}
printf("%I64d\n",maxflow(1,n,n));
}
}
HDU 1532Drainage Ditches(最大流模板题 ISAP)
原文:http://blog.csdn.net/u010372095/article/details/46446037