对于最小费用最大流,很久以前就已经学习过了,但是却早已经不记得了。
于是今天就来重新的复习一下。
对于最小费用最大流,我一直都有疑问,不知道是否有没有更高效的做法。
下面还是来简单的概述一下最小费用最大流的基本操作。
对于本题,建模并不是很难—-只需要新建一个超级源点和超级汇点即可。
图中除了与超级源点和超级汇点连接的是有向图且容量为2,权值为0.其他的点均为无向图,且容量为1.(想一想,为什么?)
这样简单的模型就建立了。
而最小费用最大流有点像最大流的做法,不断的寻找增广路,只是这个增广路是最短路,在流量允许的情况下,尽量的寻找最短路,然后不断地更新流量和最短路。有点像EK啊!
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cmath>
#define For(aa,bb,cc) for(int aa=bb;aa<=cc;++aa)
#define Set(aa,bb) memset(aa,bb,sizeof(aa))
using namespace std;
const int maxn=1010,maxm=100010,inf=0x3f3f3f3f;
int n,m,s,t;
int st[maxm],be[maxm],to[maxm],w[maxm],ne[maxm],flow[maxm],e;
int edge[maxm],dis[maxn];
bool vis[maxn];
void add(int x,int y,int z,int f){
st[++e]=x,to[e]=y,ne[e]=be[x],be[x]=e,w[e]=z,flow[e]=f;
st[++e]=y,to[e]=x,ne[e]=be[y],be[y]=e,w[e]=-z,flow[e]=0;
}
void spfa(){
Set(dis,inf),Set(vis,0),Set(edge,-1);
queue<int>q;
dis[s]=0;
q.push(s);
while(!q.empty()){
int k=q.front();q.pop(),vis[k]=0;
for(int i=be[k];i!=-1;i=ne[i]){
int u=to[i];
if(flow[i] && dis[u]>dis[k]+w[i]){
dis[u]=dis[k]+w[i];
edge[u]=i;
if(!vis[u]){
vis[u]=1;
q.push(u);
}
}
}
}
}
void bfs(){
int ans=0;
while(1){
spfa();
if(edge[t]==-1) break;
int mine=edge[t];
while(mine!=-1){
--flow[mine];
++flow[mine^1];
mine=edge[st[mine]];
}
ans+=dis[t];
}
printf("%d\n",ans);
}
void work(){
Set(be,-1);
e=-1;
scanf("%d%d",&n,&m);
For(i,1,m){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z,1);
add(y,x,z,1);
}
s=0,t=n+1;
add(s,1,0,2),add(n,t,0,2);
bfs();
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
work();
return 0;
}