标签:
首先发现每一位二进制可以分开来做。
然后就变成0、1两种数了,考虑最小割。
设S表示选0,T表示选1,则
对于确定的点向数字对应的S/T连边,边权inf;然后原来图中有边的,互相连边,边权为1。
直接最小割即可,最后还要dfs一下来求出每个未确定的数选的是0还是1。
1 /************************************************************** 2 Problem: 2400 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:552 ms 7 Memory:3180 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <algorithm> 13 14 using namespace std; 15 typedef long long ll; 16 const int N = 505; 17 const int M = 2005; 18 const int Me = 200005; 19 const int inf = 1e9; 20 21 struct edge { 22 int x, y; 23 edge() {} 24 edge(int _x, int _y) : x(_x), y(_y) {} 25 } E[M]; 26 27 struct edges { 28 int next, to, f; 29 edges() {} 30 edges(int _n, int _t, int _f) : next(_n), to(_t), f(_f) {} 31 } e[Me]; 32 33 int n, m, S, T; 34 int a[N], del[N]; 35 int tot, first[N]; 36 int d[N], q[N]; 37 ll ans; 38 39 inline int read() { 40 int x = 0, sgn = 1; 41 char ch = getchar(); 42 while (ch < ‘0‘ || ‘9‘ < ch) { 43 if (ch == ‘-‘) sgn = -1; 44 ch = getchar(); 45 } 46 while (‘0‘ <= ch && ch <= ‘9‘) { 47 x = x * 10 + ch - ‘0‘; 48 ch = getchar(); 49 } 50 return sgn * x; 51 } 52 53 inline void Add_Edges(int x, int y, int f) { 54 e[++tot] = edges(first[x], y, f), first[x] = tot; 55 e[++tot] = edges(first[y], x, 0), first[y] = tot; 56 } 57 58 bool bfs() { 59 int l, r, x, y; 60 memset(d, 0, sizeof(d)); 61 d[q[1] = S] = 1; 62 for (l = r = 1; l != (r + 1) % N; (++l) %= N) 63 for (x = first[q[l]]; x; x = e[x].next) 64 if (!d[y = e[x].to] && e[x].f) 65 d[q[(++r) %= N] = y] = d[q[l]] + 1; 66 return d[T]; 67 } 68 69 int dfs(int p, int lim) { 70 if (p == T || !lim) return lim; 71 int x, y, tmp, rest = lim; 72 for (x = first[p]; x; x = e[x].next) 73 if (d[y = e[x].to] == d[p] + 1 && (tmp = min(e[x].f, rest) > 0)) { 74 rest -= (tmp = dfs(y, tmp)); 75 e[x].f -= tmp, e[x ^ 1].f += tmp; 76 if (!rest) return lim; 77 } 78 if (lim == rest) d[p] = 0; 79 return lim - rest; 80 } 81 82 int Dinic() { 83 int res = 0; 84 while (bfs()) 85 res += dfs(S, inf); 86 return res; 87 } 88 89 void build_graph(int t) { 90 int i; 91 tot = 1, memset(first, 0, sizeof(first)); 92 for (i = 1; i <= n; ++i) 93 if (a[i] >= 0) 94 if (a[i] & t) Add_Edges(i, T, inf); 95 else Add_Edges(S, i ,inf); 96 for (i = 1; i <= m; ++i) 97 Add_Edges(E[i].x, E[i].y, 1), Add_Edges(E[i].y, E[i].x, 1); 98 } 99 100 void find(int p) { 101 int x, y; 102 d[p] = 1; 103 for (x = first[p]; x; x = e[x].next) 104 if (e[x ^ 1].f && !d[y = e[x].to]) find(y); 105 } 106 107 void calc_val(int t) { 108 int i; 109 memset(d, 0, sizeof(d)); 110 find(T); 111 for (i = 1; i <= n; ++i) 112 if (d[i]) del[i] += t; 113 } 114 115 ll calc_ans() { 116 ll res = 0; 117 int i; 118 for (i = 1; i <= n; ++i) 119 res += a[i] >= 0 ? a[i] : del[i]; 120 return res; 121 } 122 123 int main() { 124 int i; 125 n = read(), m = read(); 126 S = n + 1, T = n + 2; 127 for (i = 1; i <= n; ++i) 128 a[i] = read(); 129 for (i = 1; i <= m; ++i) 130 E[i] = edge(read(), read()); 131 for (i = 0; i <= 30; ++i) { 132 build_graph(1 << i); 133 ans += (ll) (1 << i) * Dinic(); 134 calc_val(1 << i); 135 } 136 printf("%lld\n%lld\n", ans, calc_ans()); 137 return 0; 138 }
BZOJ2400 Spoj 839 Optimal Marks
标签:
原文地址:http://www.cnblogs.com/rausen/p/4196699.html