1. 程式人生 > >POJ 2135 /// 最小費用流

POJ 2135 /// 最小費用流

題目大意:

給定一個n個點m條邊的無向圖

求從點1去點n再從點n回點1的不重疊(同一條邊不能走兩次)的最短路

 

挑戰P239

求去和回的兩條最短路很難保證不重疊

直接當做是由1去n的兩條不重疊的最短路

這樣就變成了由1去n流量為2的最小費用流

 

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N=1005;
int n,m;
struct EDGE { int v,w,c,r; };
vector <EDGE> E[N];
void addE(int u,int v,int w,int c) { E[u].push_back((EDGE){v,w,c,E[v].size()}); E[v].push_back((EDGE){u,0,-c,E[u].size()-1}); } int dis[N], pv[N] ,pe[N]; int minCFlow(int s,int t,int f) { int res=0; while(f>0) { /// Bellman-Ford求s到t最短路 memset(dis,INF,sizeof(dis)); memset(pv,
0,sizeof(pv)); dis[s]=0; bool upD=1; while(upD) { upD=0; for(int i=0;i<=n;i++) { // 通過i點 if(dis[i]==INF) continue; for(int j=0;j<E[i].size();j++) { // 更新E[i][j]點的最短路 EDGE& e=E[i][j];
if(e.w>0 && dis[e.v]>dis[i]+e.c) { // 邊容量>0才能走 dis[e.v]=dis[i]+e.c; // 找到更短的路 更新 pv[e.v]=i, pe[e.v]=j; // 記錄前驅點及邊 便於通過e.v找到i點 upD=1; } } } } if(dis[t]==INF) return -1; // s不能到t 不能增廣 int d=f; // 找到本輪實際能夠流出的流量(即實際用掉的容量) for(int i=t;pv[i];i=pv[i]) d=min(d,E[pv[i]][pe[i]].w); f-=d; // 容量消耗 res+=d*dis[t]; // 計算本輪花費 for(int i=t;pv[i];i=pv[i]) { EDGE& e=E[pv[i]][pe[i]]; e.w-=d; E[i][e.r].w+=d; } // 更新邊的容量 } return res; } int main() { while(~scanf("%d%d",&n,&m)) { int s=1, t=n; for(int i=0;i<m;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); addE(u,v,1,c); addE(v,u,1,c); // 建立u到v容量大小為1費用為c的邊 } printf("%d\n",minCFlow(s,t,2)); // 求s到t傳輸大小為2(即最大容量為2)的最小費用流 } return 0; }
View Code