基于昨天未尽的探讨,这个样子的ISAP没有使用BFS寻找最短路,而是用了头几次DFS来进行推进标号,效率降低得不多,编程复杂度确有很大改善。
简明ISAP+GAP模板:
#include<cstdio>
#include<climits>
#include<cstring>
#define MAXE 1000
#define MAXV 500
int head[MAXV];
int E,V,pos;
int vd[MAXV],d[MAXV];
inline int min(int a,int b){return a<b?a:b;}
struct edge
{
int v,f,next;
}e[MAXE*2];
void add(int u,int v,int c)
{
e[pos].v=v;
e[pos].f=c;
e[pos].next=head[u];
head[u]=pos++;
}
int dfs(int u, int flow)
{
int ret,v,tmp;
if(u == V)return flow; //找到增广路
ret = 0; //min_d:u在残量网络里相通的边的最小标号距离,初始不能变为maxint
for(int i=head[u];i!=-1;i=e[i].next) if(e[i].f>0 && d[u] == d[e[i].v] + 1) //如果是允许弧
{
tmp = dfs(e[i].v,min(flow-ret,e[i].f)); //如果找到,增广
e[i].f -= tmp;
e[i+1].f += tmp;
//由于存图方法保证逆流在顺流的下一个位置
ret += tmp;
if(ret == flow)return ret;
}
if(d[1] >= V) return ret; //如果源点的标号距离大于n,即不存在增广路,这一步放在重标号之前
vd[d[u]]--;
if(vd[d[u]] == 0)d[1] = V; //如果该标号距离的顶点是唯一的,那么删除后图出现断层
d[u]++;
vd[d[u]]++;
return ret;
}
int main()
{
freopen("in","r",stdin);
int i,u,v,c,flow,ans = 0;
while(scanf("%d%d",&E,&V)!=EOF){
pos=1;
memset(head,-1,sizeof(head));
memset(d,0,sizeof(d));
memset(vd,0,sizeof(vd));
for(i=1;i<=E;i++){
scanf("%d%d%d",&u,&v,&c);
add(u,v,c);
add(v,u,0);
}
vd[0] = V;
while(d[1] < V){
flow = dfs(1,INT_MAX);
ans += flow;
}
printf("%d\n",ans);
ans=0;
}
return 0;
}
昨天那个算法验证过是正确的ISAP,不过这个没有BFS优化,用来过时间不严格的题目吧~毕竟那么短……
今天改成了邻接表存图,应付大数据。
至此,最大流算法已化归至dfs的简明优美的形式。
Relabel-to-Front算法
这个摘自DD牛博客,还没看懂,先留下传送门:
http://cuitianyi.com/blog/%E6%B1%82%E6%9C%80%E5%A4%A7%E6%B5%81%E7%9A%84relabel-to-front%E7%AE%97%E6%B3%95/
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1024,OO=1000000000;
struct edge{
int x,y;//两个顶点
int w;//容量
int f;
edge *next,*back;
edge(){}
edge(int x,int y,int w,edge* next):x(x),y(y),w(w),f(0),next(next),back(0){}
void* operator new(size_t, void* p){
return p;
}
}*E[maxn],*cur[maxn];
int H[maxn];//高度函数
int P[maxn];//preflow
int N,S,T;
void input(){
int m;
scanf("%d%d",&m,&N);
memset(E,0,sizeof(E));
edge* data=new edge[2*m];
while(m--){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
E[x]=new((void*)data++) edge(x,y,w,E[x]);
E[y]=new((void*)data++) edge(y,x,0,E[y]);
E[x]->back = E[y];
E[y]->back = E[x];
}
S=1;
T=N;
}
template <class T>
const T& min(const T& a,const T& b){
return a<b?a:b;
}
void push(edge* e){
int u=e->x,v=e->y;
int delta=min(P[u],e->w);
e->w -= delta;
e->back->w += delta;
e->f += delta;
e->back->f = -(e->f);
P[u]-=delta;
P[v]+=delta;
}
void relabel(int u){
int minlabel=OO;
for(edge* e=E[u];e;e=e->next){
if(e->w==0)continue;
int v=e->y;
if(H[v]<minlabel){
minlabel=H[v];
cur[u]=e;
}
}
H[u]=minlabel+1;
}
void discharge(int u){
while(P[u]>0){
if(!cur[u]){
relabel(u);
}
int v=cur[u]->y;
if(cur[u]->w >0 && H[u]==H[v]+1)
push(cur[u]);
cur[u]=cur[u]->next;
}
}
void init_preflow(){
memset(H,0,sizeof(H));
memset(P,0,sizeof(P));
H[S]=N;
P[S]=OO;
for(edge* e=E[S];e;e=e->next)
push(e);
}
struct vertex{
int x;
vertex* next;
vertex(int x,vertex* next):x(x),next(next){}
vertex(){}
void* operator new(size_t, void* p){
return p;
}
};
vertex* build_list(){
vertex* data=new vertex[N-2];
vertex* L=0;
for(int i=N;i>=1;--i)
if(i!=S&&i!=T)
L=new((void*)data++) vertex(i,L);
return L;
}
int maxflow(){
memcpy(cur,E,sizeof(E));
init_preflow();
vertex* L=build_list();//list
vertex *v=L,*pre=0;
while(v){
int old_height=H[v->x];
discharge(v->x);
if(H[v->x]>old_height){
if(pre){
pre->next = v->next;
v->next = L;
L = v;
}
else;//本来就在表头
}
pre = v;
v = v->next;
}
return P[T];
}
int main(){
freopen("ditch.in","r",stdin);
freopen("ditch.out","w",stdout);
input();
int res=maxflow();
printf("%d\n",res);
}
嗯~学长说我们不是酱油队的话就必须不是酱油队啊~
加了个油~