【HDU3549】题目链接:click here
三种方法都用了一下,对比得出EK最少,只用46ms。
【Edmonds-Karp算法】
基础的最大流算法,每次BFS寻找最短路进行增广,找出一条残余路径就可以了。然后对残余网络进行增广,不要忘记正向增广,相当于负向减少,也要在图中保存记录。
最后求一个割集来得到最大流,效率O(VE2),“找任意路径”最简单的方法是用DFS,但是数据要稍微增加就会变得较慢,采用BFS,源点和汇点保存在s和t中,净流量保存在变量f中。
代码:
/*Edmonds-Karp算法
源点和汇点保持在s和t中,
净流量保持在变量f中
*/
#include <math.h>
#include <queue>
#include <deque>
#include <vector>
#include <stack>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
const double eps = 1e-6;
const double Pi = acos(-1.0);
const int maxn = 20;
const int inf=0x3f3f3f3f;
int cap[20][20],flow[20][20];// 容量。流量
int Max_flow(int t)
{
int s=1,i,j,f=0,p[20],a[20];// p代表上一个节点,a代表残量。
mem(flow,0);
queue<int> Q ;
while(1)
{
while(!Q.empty())
Q.pop();
memset(a,0,sizeof(a));
Q.push(s);
a[s]=inf;
while(!Q.empty())
{
i =Q.front();
if(i==t)
break;
Q.pop();
for(j=1; j<=t; j++)
{
if(i!=j&&!a[j]&&cap[i][j]>flow[i][j])
{
p[j]=i;
Q.push(j);
a[j]= a[i]>cap[i][j]-flow[i][j]? cap[i][j]-flow[i][j]:a[i];
}
}
}
if(!a[t]) return f;//找不到增广路,说明此时已经是最大流了。
for(i=t; i!=s; i=p[i])
{
flow[i][p[i]] -=a[t];
flow[p[i]][i] +=a[t];
}
f+=a[t];
}
}
int main()
{
int a,b,c,n,m,ncase,cas=1;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%d %d",&n,&m);
memset(cap,0,sizeof(cap));
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
if(a==b)
continue;
cap[a][b]+=c;
}
printf("Case %d: %d\n",cas++,Max_flow(n));
}
return 0;
}
【Ford-Fulkerson】
该算法是大量算法的基础,有多种实现方法。
Ford-Fulkerson算法是一种迭代算法,首先对图中所有顶点对的流大小清零,此时的网络流大小也为0。在每次迭代中,通过寻找一条“增广路径”(augument path)来增加流的值。增广路径可以看作是源点s到汇点t的一条路径,并且沿着这条路径可以增加更多的流。迭代直至无法再找到增广路径位置,此时必然从源点到汇点的所有路径中都至少有一条边的满边(即边的流的大小等于边的容量大小)。
/*Ford-Fulkerson 算法
邻接表实现
*/
#include <ctype.h>
#include <stdio.h>
#include <vector>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1101;
const int inf=0x3f3f3f3f;
struct edge
{
int to,cap,rev;
};
vector<edge > G[maxn]; //图的邻接表表示
bool used[maxn]; //访问标记
void add_edge(int from,int to,int cap)
{
G[from].push_back((edge)
{
to,cap,G[to].size()
});
G[to].push_back((edge)
{
from,0,G[from].size()-1
});
}
int dfs(int v,int t,int f)
{
if(v==t) return f;
used[v]=true;
for(int i=0; i<G[v].size(); i++)
{
edge &e=G[v][i];
if(!used[e.to]&&e.cap>0)
{
int d=dfs(e.to,t,min(f,e.cap));
if(d>0)
{
e.cap-=d;
G[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
int max_flow(int s,int t)
{
int flow=0;
for(;;)
{
memset(used,0,sizeof(used));
int f=dfs(s,t,inf);
if(f==0) return flow;
flow+=f;
}
}
int main()
{
int n,m,too,capp,revv;
int tt,j=1;
scanf("%d",&tt);
while(tt--)
{
scanf("%d%d",&m,&n);
memset(G,0,sizeof(G));
for(int i=0; i<n; i++)
{
scanf("%d%d%d",&too,&capp,&revv);
add_edge(too,capp,revv);
}
printf("Case %d: %d\n",j++,max_flow(1,m));
}
return 0;
}
【Dinic 算法】
网络流最大流的优化算法之一,每一步对原图进行分层,然后用DFS求增广路。时间复杂度是O(n^2*m) 。
算法流程
1、根据残量网络计算层次图。
2、在层次图中使用DFS进行增广直到不存在增广路。
3、重复以上步骤直到无法增广。
/*Dinic 算法
总是寻找最短路,并沿这条路增广*/
#include <math.h>
#include <queue>
#include <deque>
#include <vector>
#include <stack>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
const double eps = 1e-6;
const double Pi = acos(-1.0);
const int maxn = 18;
const int inf=0x3f3f3f3f;
struct edge
{
int from, to, cap;
};
vector<edge> EG;
vector<int> G[maxn];
int n, s, t, ans;
int level[maxn]; //顶点到源点的距离标号
int cur[maxn]; //当前弧,在其之前的边已经没有用了
void add_edge(int from, int to, int cap)
{
EG.push_back((edge)
{
from, to, cap
});
EG.push_back((edge)
{
to, from, 0
});
G[from].push_back(EG.size()-2);
G[to].push_back(EG.size()-1);
}
bool bfs()
{
mem(level,-1);
queue<int> que;
que.push(s);
level[s] = 0;
while(!que.empty())
{
int v = que.front();
que.pop();
for(int i = 0; i < G[v].size(); i++)
{
edge& e = EG[G[v][i]];
if(level[e.to] == -1 && e.cap > 0)
{
level[e.to] = level[v]+1;
que.push(e.to);
}
}
}
return (level[t]!=-1);
}
int dfs(int v, int a)
{
if(v == t || a == 0) return a;
int flow = 0, f;
for(int& i = cur[v]; i < G[v].size(); i++)
{
edge& e = EG[G[v][i]];
if(level[v]+1 == level[e.to] && (f = dfs(e.to, Min(a, e.cap))) > 0)
{
e.cap -= f;
EG[G[v][i]^1].cap += f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
void Dinic()
{
ans = 0;
while(bfs())
{
mem(cur,0);
ans += dfs(s, inf);
}
}
int main()
{
int T, m, from, to, cap,cas=1;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
while(m--)
{
scanf("%d%d%d", &from, &to, &cap);
add_edge(from, to, cap);
}
s = 1, t = n;
Dinic();
printf("Case %d: %d\n", cas++, ans);
EG.clear();
for(int i = 0; i <= n; ++i)
G[i].clear();
}
return 0;
}