题目:
http://acm.hdu.edu.cn/showproblem.php?pid=4309
题意:
方法:
用二进制枚举所有p>0的边是否修,然后按下面建图,跑最大流,输出最大的最大流及其对应的修桥费用
建图:
对于每个城市顶点i,连边S->i,流量为城市的人数
如果p<0,连u->v,流量inf;u->T,流量w
如果p==0,连u->v,流量inf;
如果p>0,如果此桥被标记修,则连u->v,流量inf;否则连u->v,流量1;
1 void solve() 2 { 3 for (int i = 0; i < (1 << rec.size()); i++) 4 { 5 tcost = 0; 6 for (int j = 0; j < rec.size(); j++) 7 if (i & (1 << j)) e[rec[j]].flag = 1, tcost += e[rec[j]].w; 8 cal(); 9 for (int j = 0; j < rec.size(); j++) 10 if (i & (1 << j)) e[rec[j]].flag = 0; 11 } 12 }
1 void build() 2 { 3 dinic.init(n + 2); 4 dinic.st = 0; 5 dinic.ed = 1; 6 for (int i = 0; i < n; i++) 7 dinic.adde(dinic.st, i + 2, a[i]); 8 for (int i = 0; i < m; i++) 9 { 10 int u = e[i].u; 11 int v = e[i].v; 12 int w = e[i].w; 13 int p = e[i].p; 14 if (p < 0) 15 { 16 dinic.adde(u + 2, v + 2, inf); 17 dinic.adde(u + 2, dinic.ed, w); 18 } 19 else if (p == 0) dinic.adde(u + 2, v + 2, inf); 20 else 21 { 22 if (e[i].flag) dinic.adde(u + 2, v + 2, inf); 23 else dinic.adde(u + 2, v + 2, 1); 24 } 25 } 26 }
代码:
1 /************************************* 2 *ACM Solutions 3 *@Author: xysmlx 4 *@Blog: http://www.cnblogs.com/xysmlx 5 *************************************/ 6 // #pragma comment(linker, "/STACK:102400000,102400000") 7 #include <cstdio> 8 #include <iostream> 9 #include <cstring> 10 #include <string> 11 #include <cmath> 12 #include <set> 13 #include <list> 14 #include <map> 15 #include <iterator> 16 #include <cstdlib> 17 #include <vector> 18 #include <queue> 19 #include <stack> 20 #include <algorithm> 21 #include <functional> 22 using namespace std; 23 typedef long long LL; 24 #define pb push_back 25 #define ROUND(x) round(x) 26 #define FLOOR(x) floor(x) 27 #define CEIL(x) ceil(x) 28 // const int maxn = 0; 29 // const int maxm = 0; 30 // const int inf = 0x3f3f3f3f; 31 const LL inf64 = 0x3f3f3f3f3f3f3f3fLL; 32 const double INF = 1e30; 33 const double eps = 1e-6; 34 const int P[4] = {0, 0, -1, 1}; 35 const int Q[4] = {1, -1, 0, 0}; 36 const int PP[8] = { -1, -1, -1, 0, 0, 1, 1, 1}; 37 const int QQ[8] = { -1, 0, 1, -1, 1, -1, 0, 1}; 38 39 /** 40 *最大流最小割:加各种优化的Dinic算法($O(V^2E)$) 41 *输入:图(链式前向星),n(顶点个数,包含源汇),st(源),ed(汇) 42 *输出:Dinic(NdFlow)(最大流),MinCut()(最小割)(需先求最大流) 43 *打印路径方法:按反向边(i&1)的flow 找,或者按边的flow找 44 */ 45 const int maxn = 510; 46 const int maxm = 20010; 47 const int inf = 0x3f3f3f3f; 48 struct DINIC 49 { 50 struct Edge 51 { 52 int u, v; 53 int cap, flow; 54 int next; 55 } edge[maxm]; 56 int head[maxn], en; //需初始化 57 int n, m, d[maxn], cur[maxn]; 58 int st, ed; 59 bool vis[maxn]; 60 void init(int _n = 0) 61 { 62 n = _n; 63 memset(head, -1, sizeof(head)); 64 en = 0; 65 } 66 void addse(int u, int v, int cap, int flow) 67 { 68 edge[en].u = u; 69 edge[en].v = v; 70 edge[en].cap = cap; 71 edge[en].flow = flow; 72 edge[en].next = head[u]; 73 head[u] = en++; 74 cur[u] = head[u]; 75 } 76 void adde(int u, int v, int cap) 77 { 78 addse(u, v, cap, 0); 79 addse(v, u, 0, 0); //注意加反向0 边 80 } 81 bool BFS() 82 { 83 queue<int> Q; 84 memset(vis, 0, sizeof(vis)); 85 Q.push(st); 86 d[st] = 0; 87 vis[st] = 1; 88 while (!Q.empty()) 89 { 90 int u = Q.front(); 91 Q.pop(); 92 for (int i = head[u]; i != -1; i = edge[i].next) 93 { 94 int v = edge[i].v; 95 int w = edge[i].cap - edge[i].flow; 96 if (w > 0 && !vis[v]) 97 { 98 vis[v] = 1; 99 Q.push(v); 100 d[v] = d[u] + 1; 101 if (v == ed) return 1; 102 } 103 } 104 } 105 return false; 106 } 107 int Aug(int u, int a) 108 { 109 if (u == ed) return a; 110 int aug = 0, delta; 111 for (int &i = cur[u]; i != -1; i = edge[i].next) 112 { 113 int v = edge[i].v; 114 int w = edge[i].cap - edge[i].flow; 115 if (w > 0 && d[v] == d[u] + 1) 116 { 117 delta = Aug(v, min(a, w)); 118 if (delta) 119 { 120 edge[i].flow += delta; 121 edge[i ^ 1].flow -= delta; 122 aug += delta; 123 if (!(a -= delta)) break; 124 } 125 } 126 } 127 if (!aug) d[u] = -1; 128 return aug; 129 } 130 int Dinic(int NdFlow) 131 { 132 int flow = 0; 133 while (BFS()) 134 { 135 memcpy(cur, head, sizeof(int) * (n + 1)); 136 flow += Aug(st, inf); 137 /*如果超过指定流量就return 掉*/ 138 if (NdFlow == inf) continue; 139 if (flow > NdFlow) break; 140 } 141 return flow; 142 } 143 /*残余网络*/ 144 void Reduce() 145 { 146 for (int i = 0; i < en; i++) edge[i].cap -= edge[i].flow; 147 } 148 /*清空流量*/ 149 void ClearFlow() 150 { 151 for (int i = 0; i < en; i++) edge[i].flow = 0; 152 } 153 /*求最小割*/ 154 vector<int> MinCut() 155 { 156 BFS(); 157 vector<int> ans; 158 for (int u = 0; u < n; u++) 159 { 160 if (!vis[u]) continue; 161 for (int i = head[u]; i != -1; i = edge[i].next) 162 { 163 if (i & 1) continue; /*忽略反向边*/ 164 int v = edge[i].v; 165 int w = edge[i].cap; 166 if (!vis[v] && w > 0) ans.push_back(i); 167 } 168 } 169 return ans; 170 } 171 } dinic; 172 173 int kase; 174 int n, m; 175 int a[maxn]; 176 int cost; 177 int flow; 178 int tcost; 179 struct Edge 180 { 181 int u, v; 182 int w; 183 int p; 184 int flag; 185 Edge(int _u, int _v, int _w, int _p): u(_u), v(_v), w(_w), p(_p) {} 186 Edge() {} 187 }; 188 vector<Edge> e; 189 vector<int> rec; 190 void init() 191 { 192 kase++; 193 e.clear(); 194 rec.clear(); 195 flow = 0; 196 cost = inf; 197 } 198 void input() 199 { 200 for (int i = 0; i < n; i++) 201 scanf("%d", &a[i]); 202 for (int i = 0; i < m; i++) 203 { 204 int u, v, w, p; 205 scanf("%d%d%d%d", &u, &v, &w, &p); 206 u--, v--; 207 e.pb(Edge(u, v, w, p)); 208 e[i].flag = 0; 209 if (p > 0) rec.pb(i); 210 } 211 } 212 void debug() 213 { 214 // 215 } 216 void build() 217 { 218 dinic.init(n + 2); 219 dinic.st = 0; 220 dinic.ed = 1; 221 for (int i = 0; i < n; i++) 222 dinic.adde(dinic.st, i + 2, a[i]); 223 for (int i = 0; i < m; i++) 224 { 225 int u = e[i].u; 226 int v = e[i].v; 227 int w = e[i].w; 228 int p = e[i].p; 229 if (p < 0) 230 { 231 dinic.adde(u + 2, v + 2, inf); 232 dinic.adde(u + 2, dinic.ed, w); 233 } 234 else if (p == 0) dinic.adde(u + 2, v + 2, inf); 235 else 236 { 237 if (e[i].flag) dinic.adde(u + 2, v + 2, inf); 238 else dinic.adde(u + 2, v + 2, 1); 239 } 240 } 241 } 242 void cal() 243 { 244 build(); 245 int tmp = dinic.Dinic(inf); 246 if (tmp > flow) 247 { 248 flow = tmp; 249 cost = tcost; 250 } 251 } 252 void solve() 253 { 254 for (int i = 0; i < (1 << rec.size()); i++) 255 { 256 tcost = 0; 257 for (int j = 0; j < rec.size(); j++) 258 if (i & (1 << j)) e[rec[j]].flag = 1, tcost += e[rec[j]].w; 259 cal(); 260 for (int j = 0; j < rec.size(); j++) 261 if (i & (1 << j)) e[rec[j]].flag = 0; 262 } 263 } 264 void output() 265 { 266 cost = cost == inf ? 0 : cost; 267 if (flow == 0) puts("Poor Heaven Empire"); 268 else printf("%d %d ", flow, cost); 269 } 270 int main() 271 { 272 // int size = 256 << 20; // 256MB 273 // char *p = (char *)malloc(size) + size; 274 // __asm__("movl %0, %%esp " :: "r"(p)); 275 276 // std::ios_base::sync_with_stdio(false); 277 #ifdef xysmlx 278 freopen("in.cpp", "r", stdin); 279 #endif 280 281 kase = 0; 282 while (~scanf("%d%d", &n, &m)) 283 { 284 init(); 285 input(); 286 solve(); 287 output(); 288 } 289 return 0; 290 }