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代码

猜你喜欢

转载自www.cnblogs.com/huyufeifei/p/10104259.html
今日推荐