题意:求两条从s->t的路径,使得两条路径不能经过相同的点和边,且两条路径长度之和最小。
其实一看到所有点和边只能经过一次,就很容易想到费用流了。拆点,将每个点拆i成(i,i')。对于原图中的每个点,连一条(i,i',1,0)的边,对于原图中的每条边(u,v),连一条(u',v,1,w)的边(w为边的权值),然后添加源S->i',cost=0,cap=2的边(S,i,2,0)的边,添加汇点T,同理,建一条(t,T,2,0)的边,跑一次最小费用最大流就可以得到答案了。
其实这题很简单,但是我比赛的时候逗比了。。居然忘记了对源点容量的限制,另一方面我费用流写的确实太少了,要记住教训啊。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <queue> 6 #define maxn 3000 7 #define maxm 30000 8 #define INF 1<<30 9 using namespace std; 10 11 struct ZKW_flow{ 12 int src,sink,e,n; 13 int first[maxn]; 14 int cap[maxm],cost[maxm],v[maxm],next[maxm]; 15 void init(){ 16 e = 2; 17 memset(first,-1,sizeof(first)); 18 } 19 20 void add_edge(int a,int b,int cc,int ww){ 21 cap[e] = cc;cost[e] = ww;v[e] = b; 22 next[e] = first[a];first[a] = e++; 23 cap[e] = 0;cost[e] = -ww;v[e] = a; 24 next[e] = first[b];first[b] = e++; 25 } 26 27 int d[maxn]; 28 29 void spfa(){ 30 for(int i = 1;i <= n;i++) d[i] = INF; 31 priority_queue<pair<int,int> > q; 32 d[src] = 0; 33 q.push(make_pair(0,src)); 34 while(!q.empty()){ 35 int u = q.top().second,dd = -q.top().first; 36 q.pop(); 37 if(d[u] != dd) continue; 38 for(int i = first[u];i != -1;i = next[i]){ 39 if(cap[i] && d[v[i]] > dd + cost[i]){ 40 d[v[i]] = dd + cost[i]; 41 q.push(make_pair(-d[v[i]],v[i])); 42 } 43 } 44 } 45 for(int i = 1;i <= n;i++) d[i] = d[sink] - d[i]; 46 } 47 48 int Mincost,Maxflow; 49 bool used[maxn]; 50 51 int add_flow(int u,int flow){ 52 if(u == sink){ 53 Maxflow += flow; 54 Mincost += d[src] * flow; 55 return flow; 56 } 57 used[u] = true; 58 int now = flow; 59 for(int i = first[u];i != -1;i = next[i]){ 60 int &vv = v[i]; 61 if(cap[i] && !used[vv] && d[u] == d[vv] + cost[i]){ 62 int tmp = add_flow(vv,min(now,cap[i])); 63 cap[i] -= tmp; 64 cap[i^1] += tmp; 65 now -= tmp; 66 if(!now) break; 67 } 68 } 69 return flow - now; 70 } 71 72 bool modify_label(){ 73 int dd = INF; 74 for(int u = 1;u <= n;u++) if(used[u]) 75 for(int i = first[u];i != -1;i = next[i]){ 76 int &vv = v[i]; 77 if(cap[i] && !used[vv]) dd = min(dd,d[vv] + cost[i] - d[u]); 78 } 79 if(dd == INF) return false; 80 for(int i = 1;i <= n;i++) if(used[i]) d[i] += dd; 81 return true; 82 } 83 84 int min_cost_flow(int ss,int tt,int nn){ 85 src = ss,sink = tt,n = nn; 86 Mincost = Maxflow = 0; 87 spfa(); 88 while(1){ 89 while(1){ 90 for(int i = 1;i <= n;i++) used[i] = 0; 91 if(!add_flow(src,INF)) break; 92 } 93 if(!modify_label()) break; 94 } 95 return Mincost; 96 } 97 }; 98 99 ZKW_flow g; 100 101 int main(){ 102 int n,m; 103 while(scanf("%d%d",&n,&m) == 2){ 104 g.init(); 105 g.add_edge(1,1+n,2,0); 106 g.add_edge(n,n+n,2,0); 107 for(int i = 2;i < n;i++) 108 g.add_edge(i,i+n,1,0); 109 for(int i = 1;i <= m;i++){ 110 int a,b,c; 111 scanf("%d%d%d",&a,&b,&c); 112 g.add_edge(a+n,b,1,c); 113 } 114 int src = 2*n+1,sink = 2*n+2; 115 g.add_edge(src,1,2,0); 116 g.add_edge(2*n,sink,2,0); 117 int ans = g.min_cost_flow(src,sink,sink+1); 118 printf("%d ",ans); 119 } 120 return 0; 121 }