csu 1506 Double Shortest Paths 最小费用最大流
题意:
两个人从1走到n
每条边走第一次花费是w1 第二次是w1+w2
问最少费用
思路:
印象中能纠正的就是最小费用最大流 就试着用了一下
每条遍分解成第一次走和第二次走两种情况
然后手动添加源点汇点 直接跑一遍模板就行了
(感谢kuangbin~
注意边都加了两遍 所以边的集合要开两倍
1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a)) 3 #define debug(x) cerr<<#x<<"=="<<(x)<<endl 4 using namespace std; 5 6 const int maxn = 500+10; 7 const int maxm = 4000+10; 8 const int inf = 0x3f3f3f3f; 9 10 struct Edge 11 { 12 int to, next, cap, flow, cost; 13 }edge[maxm]; 14 15 int n,m; 16 int head[maxn],tol; 17 int pre[maxn],dis[maxn]; 18 bool vis[maxn]; 19 20 void init() 21 { 22 tol = 0; 23 cl(head,-1); 24 } 25 26 void addedge(int u, int v, int cap, int cost) 27 { 28 edge[tol].to=v; 29 edge[tol].cap=cap; 30 edge[tol].cost=cost; 31 edge[tol].flow=0; 32 edge[tol].next=head[u]; 33 head[u]=tol++; 34 edge[tol].to=u; 35 edge[tol].cap=0; 36 edge[tol].cost=-cost; 37 edge[tol].flow=0; 38 edge[tol].next=head[v]; 39 head[v]=tol++; 40 } 41 42 bool spfa(int s, int t) 43 { 44 queue<int>q; 45 while(!q.empty()) q.pop(); 46 cl(dis,inf),cl(vis,false),cl(pre,-1); 47 dis[s] = 0; 48 vis[s] = true; 49 q.push(s); 50 while(!q.empty()) 51 { 52 int u = q.front(); 53 q.pop(); 54 vis[u] = false; 55 for(int i = head[u]; i != -1; i = edge[i]. next) 56 { 57 int v = edge[i]. to; 58 if(edge[i]. cap > edge[i]. flow && 59 dis[v] > dis[u] + edge[i]. cost ) 60 { 61 dis[v] = dis[u] + edge[i]. cost; 62 pre[v] = i; 63 if(!vis[v]) 64 { 65 vis[v] = true; 66 q.push(v); 67 } 68 } 69 } 70 } 71 if(pre[t] == -1) return false; 72 else return true; 73 } 74 75 void solve(int s, int t, int &cost) 76 { 77 int flow = 0; 78 cost = 0; 79 while(spfa(s,t)) 80 { 81 int Min = inf; 82 for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to]) 83 { 84 if(Min > edge[i]. cap - edge[i]. flow) 85 Min = edge[i]. cap - edge[i]. flow; 86 } 87 for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to]) 88 { 89 edge[i]. flow += Min; 90 edge[i^1]. flow -= Min; 91 cost += edge[i]. cost * Min; 92 } 93 flow += Min; 94 } 95 } 96 97 int main() 98 { 99 int u,v,w1,w2; 100 int cas = 0; 101 while(~scanf("%d%d",&n,&m)) 102 { 103 init(); 104 for(int i = 0; i < m; i++) 105 { 106 scanf("%d%d%d%d",&u,&v,&w1,&w2); 107 //每一条边分解成两条流量是1的边 108 //一条费用是w1 109 addedge(u,v,1,w1); 110 //另外一条是w1+w2 111 addedge(u,v,1,w1+w2); 112 } 113 //手动加入源点汇点 流量都是2 114 addedge(0,1,2,0); 115 addedge(n,n+1,2,0); 116 int ans=0; 117 solve(0,n+1,ans); 118 printf("Case %d: %d\n",++cas,ans); 119 } 120 return 0; 121 }/* 122 123 4 4 124 1 2 5 1 125 2 4 6 0 126 1 3 4 0 127 3 4 9 1 128 4 4 129 1 2 5 10 130 2 4 6 10 131 1 3 4 10 132 3 4 9 10 133 134 */