自己写的模板,稍微挫了点儿但是容易理解... 用pku 1459 测试的模板,如发现错误请留言指出
由于着急做题,只看了3种算法,Ford-Fulkerson,Edmonds-Karp(VE^2),Shortest Augment Path(SAP) (V^2 E),实现了后两种,什么dinic,预留推进之类的考完试再补吧,到时顺便复习一下。
看了别人博客,发现常用的算法分为增广路算法和预留推进算法两大类,Fulkerson,EK,SAP,dicnic都属于增广路算法,这两大类算法在算法导论里都有介绍,感觉对于我这种零基础的人《算法导论》的介绍比神牛总结的论文的效果要好...
Fulkerson是随便找一条增广路径进行增光,EK进行了优化用广搜找一条包含弧最少的增广路径(或者是权值最小的增广路径),SAP也是找最短增光路径,但是它将每个定点按距离汇点(或源点)的距离进行分类,多了一个d[i],代表顶点i所处的层数(个人理解),这个层数可以理解成广搜图的层数,那么从源点到汇点的一条最短增广路每层必须包含一个点且只能包含一个点,sap有个gap优化(间隙优化)就是基于d[i]的,我个人习惯叫gap优化为断层优化,我觉得”断层“更形象,如果某一层一个点都没有,自然就不可能找到增光路径了,sap还有一个当前弧优化,我不是很了解,不知道自己写的当前弧优化对不对...另外sap算法的时间分析我也不是很清楚,等找到论文看看论文里怎么说的吧...
Edmonds-Karp pku 1459 469ms
//网络流Edmonds-Karp算法
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define maxv 105
#define INF 0xfffffff
int n,result;
int f[maxv][maxv];//保存流
int cf[maxv][maxv];//保存残余网络
queue<int> q;
int last[maxv];
int cfp[maxv];
bool inq[maxv];//是否进过queue
bool bfs(int s,int t)
{
int i,fm,to,ans;
while(!q.empty())
q.pop();
memset(inq,0,sizeof(inq));
memset(last,0,sizeof(last));
inq[s]=1,q.push(s),cfp[s]=INF;
while(!q.empty())
{
fm=q.front();
q.pop();
for(i=1;i<=n;++i)
{
to=i;
if(cf[fm][to]&&!inq[to])
{
last[to]=fm;
inq[to]=1;
q.push(to);
cfp[to]=min(cfp[fm],cf[fm][to]);
}
}
if(inq[t])
break;
}
if(inq[t])
{
ans=cfp[t],to=t,fm=last[to];
result+=ans;
while(fm!=0)
{
cf[fm][to]-=ans;
cf[to][fm]+=ans;
f[fm][to]+=ans;
f[to][fm]=-f[fm][to];
to=fm;
fm=last[to];
}
return 1;
}
else
return 0;
}
void Edmons_Karp(int s,int t)
{
memset(f,0,sizeof(f));
result=0;
while(bfs(s,t));
return ;
}
int main()
{
int m,i,j,fm,to,cost,s,t;
while(cin>>n>>m)
{
memset(cf,0,sizeof(cf));
for(i=0;i<m;++i)
{
cin>>fm>>to>>cost;
cf[fm][to]=cost;
}
cin>>s>>t;
Edmons_Karp(s,t);
cout<<result<<endl;
}
return 0;
}
SAP+gap+cur 79ms
//shortest augment path
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxv 105
#define INF 0xfffffff
int n,pn;
int G[maxv][maxv];
int d[maxv];
int cnt[maxv]; //gap断层优化
int cur[maxv]; //cur当前弧优化
int p[maxv];
int exist(int u)
{
int i;
for(i=cur[u];i<=n;++i)
{
if(G[u][i]!=0&&d[u]==d[i]+1)
{
cur[u]=i;
return i;
}
}
return -1;
}
void aug(int &f)
{
int af=INF,i;
for(i=0;i<pn-1;++i)
af=min(af,G[p[i]][p[i+1]]);
for(i=0;i<pn-1;++i)
{
G[p[i]][p[i+1]]-=af;
G[p[i+1]][p[i]]+=af;
}
pn=0;
f+=af;
return ;
}
int renew(int u)
{
cur[u]=1;
int i,md=INF;
bool flag=false;
for(i=1;i<=n;++i)
{
if(G[u][i]!=0)
md=min(md,d[i]),flag=true;
}
if(flag)
{
cnt[d[u]]--;
if(cnt[d[u]]==0)
return -1;
cnt[md+1]++;
d[u]=md+1;
return 1;
}
else
return 0;
}
int SAP(int s,int t)
{
pn=0;
int f=0,i,j,flag;
memset(d,0,sizeof(d));
memset(cnt,0,sizeof(cnt));
cnt[0]=n;
for(i=1;i<=n;++i)
cur[i]=1;
i=s;
while(d[s]<n)
{
if((j=exist(i))!=-1)
{
p[pn++]=i;
i=j;
if(i==t)
{
p[pn++]=t;
aug(f);
i=s;
}
}
else
{
flag=renew(i);
if(flag==-1)
return f;
else if(flag==0)
d[i]=n;
if(i!=s)
i=p[--pn];
}
}
return f;
}
int main()
{
int m,i,j,fm,to,cost,s,t;
while(cin>>n>>m)
{
memset(G,0,sizeof(G));
for(i=0;i<m;++i)
{
cin>>fm>>to>>cost;
G[fm][to]=cost;
}
cin>>s>>t;
cout<<SAP(s,t)<<endl;
}
return 0;
}