1. 程式人生 > >[AHOI2014/JSOI2014]支線劇情

[AHOI2014/JSOI2014]支線劇情

min pre bit .org -- += lose names getchar()

~~~題面~~~

題解:

第一眼費用流,,然後想了好久怎麽建圖,,,最後發現是最小費用可行流的板子題。。。。

其實還沒有很懂這個算法,所以這裏只是擺一下步驟,以後再補理解吧。

首先一個思路就是轉換圖,將有上下限的圖變為普通的網絡流圖,然後再跑費用流。

所以建圖其實和有上下界的網絡流一樣的。。。

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 ----> t,流量為-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 }

[AHOI2014/JSOI2014]支線劇情