LA_6266 Admiral

题意:求两条从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\n",ans);
119     }
120     return 0;
121 }
View Code

 

posted @ 2013-10-06 14:15  浙西贫农  阅读(233)  评论(0编辑  收藏  举报