poj2135 最小费最大流
题目大意:N块田地M条道路。1为起点,N为终点,FJ从起点走到终点,经过不重复的路(可经过重复的点)再回到起点,求所花费最小时间。
建图要点: 1.要求路不重复,则使路的容量都为1.
2.从起点到终点,再从终点到起点,故建立超级源点0超级汇点N+1,建路0-1,N-N+1容量都为2。
3.有重边,所以要用邻接表。
4.无向图,所以每条边都要建立正反两边。又因为一条路可能是从起点到终点时经过,也可能是从终点到起点时经过,所以还要建立反向的正反两边,一共4边。
5.因为此题是无向图,所以建边的时候如果建两条费用都是正的边的话,退流时无法修正费用。
1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cstdio> 7 #include <string> 8 #include <vector> 9 #include <queue> 10 #include <cmath> 11 #include <stack> 12 #include <map> 13 #include <cmath> 14 #include <set> 15 #include <climits> 16 #define INF 0x7fffffff 17 #define finc(i,a,b) for(i=a;i<=b;i++) 18 #define fdec(i,a,b) for(i=a;i>=b;i--) 19 #define MAXN 10001 20 #define MAXM 100002 21 using namespace std; 22 int N,M,Source,ans; 23 struct E //使用数组模拟邻接表存储边信息 24 { 25 int b,cost,cap,next; 26 }edge[MAXM]; 27 28 int list[MAXN],tot,p[MAXN],pre[MAXN],qe[MAXN]; 29 int dist[MAXN]; 30 queue<int>q; 31 int cnt[MAXN]; 32 bool f[MAXN]; 33 34 void add(int a,int b,int cap,int cost) //构建邻接表 35 { 36 37 edge[tot].b=b; edge[tot].cap=cap; edge[tot].cost=cost; 38 edge[tot].next=list[a]; list[a]=tot++; 39 edge[tot].b=a; edge[tot].cap=0; edge[tot].cost=-cost; 40 edge[tot].next=list[b]; list[b]=tot++; 41 } 42 void init() 43 { 44 cin>>N>>M; 45 for(int i=1;i<=M;i++) 46 { 47 int a,b,cost; 48 cin>>a>>b>>cost; 49 add(a,b,1,cost); 50 add(b,a,1,cost); 51 } 52 } 53 54 bool spfa() //求最小费最短路 55 { 56 memset(f,0,sizeof(f)); 57 memset(pre,-1,sizeof(pre)); 58 // memset(cnt,0,sizeof(cnt)); 59 for(int i=1;i<=N+1;i++) 60 dist[i]=INF; 61 dist[Source]=0;pre[0]=0; 62 q.push(Source);f[Source]=0; 63 while(q.size()) 64 { 65 int a=q.front(),b; 66 q.pop(); 67 for(int k=list[a]; k!=-1; k=edge[k].next) 68 { 69 b=edge[k].b; 70 if(edge[k].cap&& dist[b]>dist[a]+edge[k].cost ) 71 { 72 dist[b]=dist[a]+edge[k].cost; 73 74 if(f[b] == 0) 75 { 76 f[b]=1; 77 q.push(b); 78 } 79 pre[b]=a; ///记录前导后导,用于退流 80 qe[b]=k; 81 } 82 } 83 f[a]=0; 84 } 85 if(pre[N+1] == -1) return false; 86 else return true; 87 } 88 void end() 89 { 90 int i,tmp=INF; 91 for(i=N+1;i!=0;i=pre[i]) 92 tmp=min(tmp,edge[qe[i]].cap); 93 ans+=dist[N+1]*tmp; ///单位费用乘流量 94 for(i=N+1;i!=0;i=pre[i]){ 95 edge[qe[i]].cap-=tmp; 96 edge[qe[i]^1].cap+=tmp; 97 } 98 } 99 int main() 100 { 101 memset(list,-1,sizeof(list)); 102 tot=0;ans=0; Source=0; 103 init(); 104 add(0,1,2,0); 105 add(N,1+N,2,0); 106 107 108 109 while(spfa()){ 110 end(); 111 // cout<<ans<<endl; 112 } 113 printf("%d\n",ans); 114 }