HDU 4067 Random Maze

题意:给出一张有向图,现在要你删去一些边构造一张新图,新图的要求有

1.对于起点s,出度-入度=1.

2.对于终点t,入度-出度=1.

3.对于其余的点,入度=出度.

另外,保留每条边需要花费ai,删掉每条边需要花费bi。

现在求一个最小花费的方案使得能够构造出符合要求的图。

看到这题首先想到以前做过的几个混合图欧拉回路的问题,因为本题跟混合图欧拉回路有一些类似的地方,比如说,我无法去控制每个点具体的出度入度到底是多少,但是可以知道它们之间的关系。并且对于每条边,我都不知道到底该不该留,所以可能会考虑先假定它到底是留下还是不留,然后利用每个点度数的关系跟源汇相连,用网络流去求解一个方案。

所以本题就应该是一个费用流的问题。具体操作起来的话,如果把这些边全部假定留下,然后考虑如果要删去这条边,这个费用就可能是负的也可能是正的了。这样一建图,如果建出个有费用负圈的,就跪了。。所以不能这样建图。其实费用肯定会有一个下界。

我默认费用小的方案为初始方案,即对每条边(u,v,a,b),如果b>=a,那么我默认它留下,费用下限sum+=a,删去此边的额外费用是b-a,对应一条边(u,v,1,b-a),in(v)++,out(u)++。

同理,如果a>b,那么我默认它应该删去,费用下限sum+=b,保留此边的额外费用是a-b,对应边(v,u,1,a-b)。这条边肯定跟原来的边是反向的,因为这条边如果是需要的,那肯定是因为u的出度多了,应该多入一个。

再接下来,利用前面默认统计的每个点的出度、入度再跟源汇相连构造网络流了。设val=in(i)-out(i),如果i是起点s,val额外+1,如果i是汇点,val额外-1。如果val>0,那么对应边(i,T,val,0),否则对应边(S,i,val,0)。

构造完后跑费用流,如果满流,那么最小费用+费用下限sum就是答案,否则就是impossible。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <queue>
  5 #define maxn 110
  6 #define maxm 100000
  7 #define INF 1<<30
  8 using namespace std;
  9 struct MCMF{
 10     int src,sink,e,n;
 11     int first[maxn];
 12     int cap[maxm],cost[maxm],v[maxm],next[maxm];
 13     void init(){
 14         e = 0;
 15         memset(first,-1,sizeof(first));
 16     }
 17     void add_edge(int a,int b,int cc,int ww){
 18         //printf("add:%d to %d,cap = %d,cost = %d
",a,b,cc,ww);
 19         v[e] = b;next[e] = first[a];cap[e] = cc;
 20         cost[e] = ww;first[a] = e++;
 21         v[e] = a;next[e] = first[b];cap[e] = 0;
 22         cost[e] = -ww;first[b] = e++;
 23     }
 24 
 25     int d[maxn],pre[maxn],pos[maxn];
 26     bool vis[maxn];
 27 
 28     bool spfa(int s,int t){
 29         memset(pre,-1,sizeof(pre));
 30         memset(vis,0,sizeof(vis));
 31         queue<int> Q;
 32         for(int i = 0;i <= n;i++)   d[i] = INF;
 33         Q.push(s);pre[s] = s;d[s] = 0;vis[s] = 1;
 34         while(!Q.empty()){
 35             int u = Q.front();Q.pop();
 36             vis[u] = 0;
 37             for(int i = first[u];i != -1;i = next[i]){
 38                 if(cap[i] > 0 && d[u] + cost[i] < d[v[i]]){
 39                     d[v[i]] = d[u] + cost[i];
 40                     pre[v[i]] = u;pos[v[i]] = i;
 41                     if(!vis[v[i]])  vis[v[i]] = 1,Q.push(v[i]);
 42                 }
 43             }
 44         }
 45         return pre[t] != -1;
 46     }
 47 
 48     int Mincost,Maxflow;
 49     int MincostFlow(int s,int t,int nn){
 50         Mincost = Maxflow = 0,n = nn;
 51         while(spfa(s,t)){
 52             int min_f = INF;
 53             for(int i = t;i != s;i = pre[i])
 54                 if(cap[pos[i]] < min_f) min_f = cap[pos[i]];
 55             Mincost += d[t] * min_f;
 56             Maxflow += min_f;
 57             for(int i = t;i != s;i = pre[i]){
 58                 cap[pos[i]] -= min_f;
 59                 cap[pos[i]^1] += min_f;
 60             }
 61         }
 62         return Mincost;
 63     }
 64 };
 65 MCMF g;
 66 int in[maxn],out[maxn];
 67 
 68 int main()
 69 {
 70     int n,m,s,t,nkase;
 71     scanf("%d",&nkase);
 72     for(int kase = 1;kase <= nkase;kase++){
 73         g.init();
 74         scanf("%d%d%d%d",&n,&m,&s,&t);
 75         int S = 0,T = n+1;
 76         memset(in,0,sizeof(in));
 77         memset(out,0,sizeof(out));
 78         int sum = 0,cnt = 0;
 79         for(int i = 0;i < m;i++){
 80             int from,to,a,b;
 81             scanf("%d%d%d%d",&from,&to,&a,&b);
 82             if(a <= b){
 83                 in[to]++,out[from]++;
 84                 g.add_edge(from,to,1,b-a);
 85                 sum += a;
 86             }else{
 87                 g.add_edge(to,from,1,a-b);
 88                 sum += b;
 89             }
 90         }
 91         for(int i = 1;i <= n;i++){
 92             int val = in[i]-out[i];
 93             if(i == s)  val++;
 94             if(i == t)  val--;
 95             if(val > 0){
 96                 g.add_edge(i,T,val,0);
 97                 cnt += val;
 98             }else{
 99                 g.add_edge(S,i,-val,0);
100             }
101         }
102         int ans = sum + g.MincostFlow(S,T,T);
103         if(g.Maxflow == cnt){
104             printf("Case %d: %d
",kase,ans);
105         }else{
106             printf("Case %d: impossible
",kase);
107         }
108     }
109     return 0;
110 }
View Code
原文地址:https://www.cnblogs.com/zhexipinnong/p/3426051.html