生活随笔
收集整理的這篇文章主要介紹了
最小费用最大流总结
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
最小費用最大流
在費用流的圖上,邊不僅有流量還有權(quán)值。
最小費用最大流就是在最大流不唯一時,求權(quán)值最小的方案,其基本思想就是在最大流的基礎(chǔ)上考慮費用最小。解決這種問題的操作可以描述為多次迭代的過程,下面來介紹解決這種問題的一種方法——Spfa增廣。
Spfa增廣
基本思想是:從零流為初始可行流開始,在每次迭代過程中對每條邊賦予與cap(容量)、w(單位流量運輸費用)、flow(現(xiàn)有流的流量)有關(guān)的權(quán)數(shù)dis(i,j),形成一個有向賦權(quán)圖。再用Spfa確定由s到t的費用最小的非飽和路,沿著該路增加流量,得到相應(yīng)的新流。經(jīng)過多次迭代,直至達到最大流為止。
因為沒有找到很好的裸題,所以選了Hdu 2135,一道類最短路問題。
因為從起點出發(fā)走到終點還要再回起點,所以要把起點終點拆掉,建一條容量為2的邊。
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn=
1005,maxm=
40005;
int lnk[maxn],son[maxm],fa[maxm],nxt[maxm],cap[maxm],flow[maxm],f[maxm];
int n,m,tot,w[maxm],que[maxn],hed,til,dis[maxn],p[maxn],ans,INF;
bool vis[maxn];
void add(
int x,
int y,
int c,
int z){nxt[tot]=lnk[x];lnk[x]=tot;fa[tot]=x;son[tot]=y;w[tot]=z;cap[tot]=c;tot++;nxt[tot]=lnk[y];lnk[y]=tot;fa[tot]=y;son[tot]=x;w[tot]=-z;cap[tot]=
0;tot++;
}
int mi(
int x,
int y){
if (x<y)
return x;
return y;}
bool spfa(){
memset(vis,
0,
sizeof(vis));
memset(dis,
63,
sizeof(dis));
memset(p,
63,
sizeof(p));hed=
0;til=
1;que[
1]=
0;INF=dis[
0];vis[
0]=
1;dis[
0]=
0;
while (hed!=til){
int x=que[hed=(hed+
1)%maxn];vis[x]=
0;
for (
int j=lnk[x];j!=-
1;j=nxt[j])
if (cap[j]>flow[j]&&dis[x]+w[j]<dis[son[j]]){dis[son[j]]=dis[x]+w[j];f[son[j]]=j;p[son[j]]=mi(p[x],cap[j]-flow[j]);
if (!vis[son[j]]){que[til=(til+
1)%maxn]=son[j];vis[son[j]]=
1;}}}
if (dis[n+
1]==INF)
return 0;ans+=dis[n+
1]*p[n+
1];
for (
int i=n+
1;i;i=fa[f[i]]) flow[f[i]]+=p[n+
1],flow[f[i]^
1]-=p[n+
1];
return 1;
}
int main(){freopen(
"exam.in",
"r",stdin);freopen(
"exam.out",
"w",stdout);
memset(lnk,
255,
sizeof(lnk));
scanf(
"%d%d",&n,&m);add(
0,
1,
2,
0);add(n,n+
1,
2,
0);
while (m--){
int x,y,z;
scanf(
"%d%d%d",&x,&y,&z);add(x,y,
1,z);add(y,x,
1,z);}
while (spfa());
printf(
"%d\n",ans);
return 0;
}
總結(jié)
以上是生活随笔為你收集整理的最小费用最大流总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。