1. 程式人生 > >bzoj3698 XWW的難題

bzoj3698 XWW的難題

題意:給你個n * n的實數矩陣,你需要把它中的每個數上/下取整,並滿足如下條件:

每行最後一個數等於前面的和。

每列最後一個數等於前面的和。

n行n列的那個元素始終為0,不予考慮。

求滿足條件下矩陣中元素的最大總和是多少。

解:

首先假設全部下取整。

s->行->列->t連邊,可以發現每條邊都有上下界。

有源匯有上下界最大流。

出來的最大流*3就是答案。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <queue>
  4 #include <cstring>
  5
6 const int N = 210, M = 1000010, INF = 0x3f3f3f3f; 7 8 struct Edge { 9 int nex, v, c; 10 }edge[M << 1]; int top = 1; 11 12 int e[N], d[N], ot[N]; 13 std::queue<int> Q; 14 15 inline void add(int x, int y, int z) { 16 top++; 17 edge[top].v = y; 18 edge[top].c = z;
19 edge[top].nex = e[x]; 20 e[x] = top; 21 22 top++; 23 edge[top].v = x; 24 edge[top].c = 0; 25 edge[top].nex = e[y]; 26 e[y] = top; 27 return; 28 } 29 30 inline bool BFS(int s, int t) { 31 memset(d, 0, sizeof(d)); 32 d[s] = 1; 33 Q.push(s); 34
while(!Q.empty()) { 35 int x = Q.front(); 36 Q.pop(); 37 for(int i = e[x]; i; i = edge[i].nex) { 38 int y = edge[i].v; 39 if(!edge[i].c || d[y]) { 40 continue; 41 } 42 d[y] = d[x] + 1; 43 Q.push(y); 44 } 45 } 46 return d[t]; 47 } 48 49 int DFS(int x, int t, int maxF) { 50 if(x == t) { 51 return maxF; 52 } 53 int ans = 0; 54 for(int i = e[x]; i; i = edge[i].nex) { 55 int y = edge[i].v; 56 if(!edge[i].c || d[x] + 1 != d[y]) { 57 continue; 58 } 59 int temp = DFS(y, t, std::min(edge[i].c, maxF - ans)); 60 if(!temp) { 61 d[y] = INF; 62 } 63 ans += temp; 64 edge[i].c -= temp; 65 edge[i ^ 1].c += temp; 66 if(ans == maxF) { 67 break; 68 } 69 } 70 return ans; 71 } 72 73 inline int solve(int s, int t) { 74 int ans = 0; 75 while(BFS(s, t)) { 76 ans += DFS(s, t, INF); 77 } 78 return ans; 79 } 80 81 int main() { 82 int n; 83 scanf("%d", &n); 84 int s = n * 2 + 1, t = n * 2 + 2, ss = n * 2 + 3, tt = n * 2 + 4; 85 for(int i = 1; i <= n; i++) { 86 for(int j = 1; j <= n; j++) { 87 double y; 88 scanf("%lf", &y); 89 int x = (int)(y); 90 if(i < n && j < n) { 91 // add (i, n + j, x) 92 ot[i] += x; 93 ot[n + j] -= x; 94 } 95 else if(i < n) { 96 // add (s, i, x) 97 ot[s] += x; 98 ot[i] -= x; 99 } 100 else if(j < n) { 101 // add(n + j, t, x) 102 ot[n + j] += x; 103 ot[t] -= x; 104 } 105 if(x < y) { 106 if(i < n && j < n) { 107 add(i, n + j, 1); 108 } 109 else if(i < n) { 110 add(s, i, 1); 111 } 112 else if(j < n) { 113 add(n + j, t, 1); 114 } 115 } 116 } 117 } 118 int sum = 0; 119 for(int i = 1; i <= t; i++) { 120 if(ot[i] > 0) { 121 add(i, tt, ot[i]); 122 } 123 else if(ot[i] < 0) { 124 add(ss, i, -ot[i]); 125 sum -= ot[i]; 126 } 127 } 128 add(t, s, INF); 129 130 int ans = solve(ss, tt); 131 if(ans != sum) { 132 puts("No"); 133 return 0; 134 } 135 136 for(int i = e[ss]; i; i = edge[i].nex) { 137 edge[i].c = edge[i ^ 1].c = 0; 138 } 139 for(int i = e[tt]; i; i = edge[i].nex) { 140 edge[i].c = edge[i ^ 1].c = 0; 141 } 142 //edge[top].c = edge[top - 1].c = 0; 143 144 ans = solve(s, t); 145 //printf("ans + cost %d + %d \n", ans * 3, cost); 146 printf("%d", ans * 3); 147 148 return 0; 149 }
AC程式碼