[AHOI2014/JSOI2014]支线剧情 有上下界费用流

~~~题面~~~

题解:

第一眼费用流,,然后想了好久怎么建图,,,最后发现是最小费用可行流的板子题。。。。

其实还没有很懂这个算法,所以这里只是摆一下步骤,以后再补理解吧。

首先一个思路就是转换图,将有上下限的图变为普通的网络流图,然后再跑费用流。

所以建图其实和有上下界的网络流一样的。。。

1,首先建立超级源点汇点ss和tt

2,对于原图中每一条边x ---> y,设其上下界为(l, r),费用为cost,那么连边的时候将流量变为r - l即可

3,对于任意点i,记d[i]为它的富余流量,即入度的下界和 - 出度的下界和。

  若d[i] > 0,则连边ss ----> i, 流量为d[i] , 费用0

  若d[i] < 0,则连边i ----> tt,流量为-d[i],费用0

4,连边t ---> s,流量inf,费用0

答案即为ans + 所有边下界 * 边的费用

其实可以感性的理解为先有了一个不一定合法的解(下界*费用),然后再利用费用流使用最小的代价使得答案合法。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 400
  5 #define ac 100000
  6 #define inf 2139062143
  7 #define getchar() *o++
  8 char READ[5001000], *o = READ;
  9 int n, ans, s, t1, t;
 10 int last[AC], dis[AC], disflow[AC], d[AC];
 11 int date[ac], Next[ac], haveflow[ac], cost[ac], Head[AC], tot = 1;
 12 bool z[AC];
 13 deque<int> q;
 14 
 15 inline int read()
 16 {
 17     int x=0;char c=getchar();
 18     while(c > '9' || c < '0') c = getchar();
 19     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
 20     return x;
 21 }
 22 
 23 inline void add(int f,int w,int S,int C)
 24 {
 25     date[++tot] = w, Next[tot] = Head[f], haveflow[tot] = S, cost[tot] = C, Head[f] = tot;
 26     date[++tot] = f, Next[tot] = Head[w], cost[tot] = -C, Head[w] = tot;
 27     //printf("%d %d %d %d\n",f,w,S,C);
 28 }
 29 
 30 void pre()
 31 {
 32     int a,b,c;
 33     n=read();
 34     t1 = n + 1, s = n + 2, t = n + 3;
 35     for(R i=1;i<=n;i++)
 36     {
 37         a=read();
 38         for(R j=1;j<=a;j++)
 39         {
 40             b=read(),c=read();
 41             --d[i], ++d[b];
 42             ans += c;
 43             add(i, b, inf, c);
 44         }
 45     }
 46     for(R i=2;i<=n;i++) 
 47         add(i, t1, inf, 0);
 48     for(R i=1;i<=n;i++)
 49     {
 50         if(d[i] > 0) add(s, i, d[i], 0);
 51         if(d[i] < 0) add(i, t, -d[i], 0);
 52     }    
 53     add(t1, 1, inf, 0);//是费用为0!
 54 }
 55 
 56 inline void aru()
 57 {
 58     int x = t;
 59     while(x != s)
 60     {
 61         haveflow[last[x]] -= disflow[t];
 62         haveflow[last[x] ^ 1] += disflow[t];
 63         x = date[last[x] ^ 1];
 64     }
 65     ans += disflow[t] * dis[t];    
 66 }
 67 
 68 bool spfa()
 69 {
 70     int x, now;
 71     dis[s] = 0, disflow[s] = inf, z[s] = true;
 72     q.push_front(s);
 73     while(!q.empty())
 74     {
 75         x = q.front();
 76         q.pop_front();
 77         z[x] = false;//标记出列
 78         for(R i=Head[x]; i ;i=Next[i])
 79         {
 80             now = date[i];
 81             if(haveflow[i] && dis[now] > dis[x] + cost[i])
 82             {//要有流量啊
 83                 dis[now] = dis[x] + cost[i];
 84                 last[now] = i;
 85                 disflow[now] = min(disflow[x], haveflow[i]);
 86                 if(!z[now])
 87                 {
 88                     z[now] = true;
 89                     if(!q.empty() && dis[now] < q.front()) q.push_front(now);
 90                     else q.push_back(now);
 91                 }
 92             }
 93         }
 94     }
 95     if(dis[t] != inf) aru();
 96     return dis[t] != inf;
 97 }
 98 
 99 bool spfa1()
100 {
101     int x,now;
102     z[s]=true,dis[s]=0,disflow[s]=inf;
103     q.push_front(s);
104     while(!q.empty())
105     {
106         x=q.front();
107         q.pop_front();
108         z[x]=false;
109         for(int i=Head[x]; i ;i=Next[i])
110         {
111             now=date[i];
112             if(haveflow[i] && dis[now]>dis[x]+cost[i])
113             {
114                 dis[now]=dis[x]+cost[i];
115                 last[now]=i;
116                 disflow[now]=min(disflow[x],haveflow[i]);//以点为单位记录到这个点时的流量
117                 if(!z[now]) 
118                 {
119                     z[now] = true;
120                     q.push_front(now);
121                 }
122                 /*if(!z[now] && now!=t)
123                 {
124                     if(!q.empty() && dis[now]<dis[q.front()])    q.push_front(now);
125                     else q.push_back(now);
126                     z[now]=true;
127                 }*/
128             }
129         }
130     }
131     //更新路径
132     if(dis[t] != inf) aru();
133     return dis[t] != inf;
134 }
135 
136 void work()
137 {
138     //printf("%d\n",ans);
139     memset(dis, 127, sizeof(dis));
140     while(spfa())
141         memset(dis, 127, sizeof(dis));
142     printf("%d\n",ans);
143 }
144 
145 int main()
146 {
147 //    freopen("in.in","r",stdin);
148     fread(READ, 1, 5000000, stdin);
149     pre();
150     work();
151 //    fclose(stdin);
152     return 0;
153 }

 

posted @ 2018-06-13 08:50  ww3113306  阅读(292)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。