思路:最大流的裸题,此题数据较小,用 E d m o n d s − K a r p Edmonds-Karp Edmonds−Karp算法较方便。
第一次写记录一下算法的实现:
增广路径:从源点(类似起点)到汇点(类似终点) 的一条可行流的路径。
1.寻找增广路径并记录增广路径,找到在该路径上的最大流。
2.加上该贡献,然后对其路径建立反路径, (保证有反悔性质的贪心,得到最优解。)
3.直到找不到增广路径推出循环,返回总贡献值。
时间复杂度: O ( n m 2 ) O(nm^2) O(nm2), n , m n,m n,m分别为结点数,边数。
复杂度证明:因为 b f s bfs bfs一次,需要 O ( m ) O(m) O(m)的复杂度,总共需要 b f s O ( n m ) bfs\ O(nm) bfs O(nm)次。
所以时间复杂度为: O ( n m 2 ) O(nm^2) O(nm2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=205,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
int n,m,st,ed,pre[N],g[N][N]; //pre[i] 记录路径.
int bfs(){ //求增广路的最大流速.
int flow[N]; //保存流速.
mst(pre);
queue<int>q;
q.push(st);
flow[st]=inf;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=1;i<=n;i++){
if(i!=st&&g[u][i]&&!pre[i]){
pre[i]=u;
q.push(i);
flow[i]=min(flow[u],g[u][i]);
}
}
}
return pre[ed]?flow[ed]:-1;
}
int EK_flow(){
int ans=0;
while(1){
int flow=bfs();
if(flow==-1) break;//没有增广路说明当前已经是最大流.
int now=ed;
while(now!=st){
int fa=pre[now];
g[fa][now]-=flow;
g[now][fa]+=flow; //重点:对残留网络建立反向路径
now=fa;
}
ans+=flow;
}
return ans;
}
int main(){
while(~scanf("%d%d",&m,&n)){
mst(g);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
g[u][v]+=w; //重边要将流速叠加起来
}
st=1,ed=n;
printf("%d\n",EK_flow());
}
return 0;
}