對於最小費用最大流問題,它的重點就在於 「增廣路」 什麼是 增廣路? 就是在以找的的路的基礎上再加一條路 加上這條路能讓結果更大,直接使用 Dijkstra 能找的的路是最短的路,繼續用能找到剩下路中間的最小路, 可是這兩條路加上來不必定是整體的最小路 ,第一次 1->3 ->5->4->6 第二次1->2->6 這並非咱們須要的結果,因此在找第二條最短路時,咱們須要能反悔,能不html
讓第一次不走3->5,怎麼反悔,在構建圖時加上一條反邊,第一次走了多少正邊減小多少反邊加上多少,這樣第二次就能夠走5->3而後走3->6這條線,第一次走了3->5,第二次湊了5->3至關與反悔了第一次的路,這樣就能儘量的走最小路。ios
#include<iostream> #include<cstring> #include<queue> using namespace std; /*6 11 1 2 23 1 3 12 1 4 99 2 5 17 2 6 73 3 5 3 3 6 21 4 6 8 5 2 33 5 4 5 6 5 20*/ #define MAX 23060 int MinCos; int v,cnt; int Head[MAX]; int Next[MAX]; int F[MAX];//流量 int To[MAX];//終結的 int Dis[MAX]; int Cos[MAX];//花費 int vis[MAX]; void _add(int a,int b,int f,int c) { cnt++; F[cnt]=f; To[cnt]=b; Cos[cnt]=c; Next[cnt]=Head[a]; Head[a]=cnt; } void add(int a,int b,int c)//增長點 用於構圖 { if(!vis[a]&&a!=1&&a!=v) { _add(a,a+v,1,0); _add(a+v,a,0,0); vis[a]=1; } if(!vis[b]&&b!=1&&b!=v) { _add(b,b+v,1,0); _add(b+v,b,0,0); vis[b]=1; } if(a==1||b==v) { if(a!=1&&b==v) { _add(a+v,b,1,c); _add(b,a+v,0,-c); }else if(a==1&&b!=v) { _add(a,b,1,c); _add(b,a,0,-c); } else { _add(a,b,1,c); _add(b,a,0,-c); } }else if(a==v||b==1){} else { _add(a+v,b,1,c); _add(b,a+v,0,-c); } } void Dijks(int folw)//Dijks求最小費用最大流算法 { priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >sp; int h[MAX]; To[MAX-1]=1; memset(h,0,sizeof(h)); while(folw>0) { memset(Dis, 0x3f3f3f3f, sizeof(Dis)); memset(vis,0,sizeof(vis)); Dis[1] = 0; pair<int, int> t; sp.push(make_pair(0,MAX-1)); int pre[MAX]; pre[1] = 0; while (!sp.empty()) { t = sp.top(); sp.pop(); int to = To[t.second]; if(to==v)continue; if(vis[to])continue; if (Dis[to] < t.first)continue;//剪枝 vis[to]=1; for (int i = Head[to]; i != -1; i = Next[i]) { if (F[i] && Dis[To[i]] > Dis[to] + h[to] - h[To[i]] + Cos[i]) {//跟新最小費用 Dis[To[i]] = Dis[to] + h[to] - h[To[i]] + Cos[i]; pre[i]=t.second;//記錄上一個節點 if(To[i]==v) { pre[MAX-2]=i; } sp.push(make_pair(Dis[To[i]], i)); } } } if(Dis[v]==0x3f3f3f3f)break; for (int i = 1; i <= 2*v; i++) { h[i] += Dis[i];//我也不是能理解可是有篇博客寫的特別好 } for(int i=pre[MAX-2];i!=MAX-1;i=pre[i])//求最小費用 { MinCos+=Cos[i]; F[i] -= 1;//存入數據時0開始,偶數存正向邊,奇數反向邊 F[i ^ 1] += 1;//i^1就是奇數 } folw -= 1; } cout<<MinCos<<"\n"; } int main() { ios::sync_with_stdio(false); cin.tie(0); int p; while(cin>>v>>p) { for(int i=0;i<20060;i++) { F[i]=0; To[i]=0; Dis[i]=0; Cos[i]=0; vis[i]=0; Head[i]=-1; Next[i]=-1; } MinCos=0; cnt=-1; for (int i = 0; i < p; i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } Dijks(2); } return 0; }
一個大佬講解h[i]函數的博客http://www.cppblog.com/guojingjia2006/archive/2009/11/12/57905.html算法