洛谷P4486 Kakuro

题意:你有一个棋盘,某些格子是限制条件,形如"从这里开始下面所有连续空格的和为a"或"从这里开始向右的所有连续空格之和为b"一个格子可以同时拥有两个限制条件。

每个数都必须是正整数。

现在你可以把某些格子加/减1,并花费相应的代价。可以操作无数次。求把棋盘变得合法的最小代价。

解:没想出来,看了题解......

一开始想了数字和条件构成二分图,又想了行列连边,但是始终建不出图来。

行列连边。

因为既可以加又可以减不好搞,我们可以先全部转换成满足条件的最小值,然后往上加。

从最小值到初始值的时候,边权为负。之后边权为正。

不可修改的地方边权为INF。

然后跑一个最小费用可行流就是答案。

如何判断无解?

考虑每条边,如果有的边费用为INF但是有流量,就不合法。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <queue>
  4 #include <cstring>
  5 
  6 typedef long long LL;
  7 const LL N = 2000, M = 1000010, INF = 0x3f3f3f3f, J = 35;
  8 
  9 struct Edge {
 10     LL nex, v, c, len;
 11 }edge[N << 1]; LL top = 1;
 12 
 13 LL e[N], d[N], vis[N], pre[N], flow[N];
 14 std::queue<LL> Q;
 15 LL fr[J][J], val[J][J], v2[J][J], cst[J][J], c2[J][J], m;
 16 
 17 inline void add(LL x, LL y, LL z, LL w) {
 18     top++;
 19     edge[top].v = y;
 20     edge[top].c = z;
 21     edge[top].len = w;
 22     edge[top].nex = e[x];
 23     e[x] = top;
 24 
 25     top++;
 26     edge[top].v = x;
 27     edge[top].c = 0;
 28     edge[top].len = -w;
 29     edge[top].nex = e[y];
 30     e[y] = top;
 31     return;
 32 }
 33 
 34 inline bool SPFA(LL s, LL t) {
 35     memset(d, 0x3f, sizeof(d));
 36     d[s] = 0;
 37     flow[s] = INF;
 38     vis[s] = 1;
 39     Q.push(s);
 40     while(!Q.empty()) {
 41         LL x = Q.front();
 42         Q.pop();
 43         vis[x] = 0;
 44         for(LL i = e[x]; i; i = edge[i].nex) {
 45             LL y = edge[i].v;
 46             if(edge[i].c && d[y] > d[x] + edge[i].len) {
 47                 d[y] = d[x] + edge[i].len;
 48                 pre[y] = i;
 49                 flow[y] = std::min(flow[x], edge[i].c);
 50                 if(!vis[y]) {
 51                     vis[y] = 1;
 52                     Q.push(y);
 53                 }
 54             }
 55         }
 56     }
 57     return d[t] < INF;
 58 }
 59 
 60 inline void update(LL s, LL t) {
 61     LL temp = flow[t];
 62     while(t != s) {
 63         LL i = pre[t];
 64         edge[i].c -= temp;
 65         edge[i ^ 1].c += temp;
 66         t = edge[i ^ 1].v;
 67     }
 68     return;
 69 }
 70 
 71 inline LL solve(LL s, LL t, LL &cost) {
 72     LL ans = 0;
 73     cost = 0;
 74     while(SPFA(s, t)) {
 75         if(d[t] > 0) {
 76             break;
 77         }
 78         ans += flow[t];
 79         cost += flow[t] * d[t];
 80         update(s, t);
 81     }
 82     return ans;
 83 }
 84 
 85 inline LL id(LL x, LL y) {
 86     return (x - 1) * m + y;
 87 }
 88 
 89 int main() {
 90     LL n, use = 0;
 91     scanf("%lld%lld", &n, &m);
 92     for(LL i = 1; i <= n; i++) {
 93         for(LL j = 1; j <= m; j++) {
 94             scanf("%lld", &fr[i][j]);
 95         }
 96     }
 97     for(LL i = 1; i <= n; i++) {
 98         for(LL j = 1; j <= m; j++) {
 99             if(fr[i][j] == 0) {
100                 continue;
101             }
102             else if(fr[i][j] == 1) {
103                 scanf("%lld", &val[i][j]);
104             }
105             else if(fr[i][j] == 2) {
106                 scanf("%lld", &v2[i][j]);
107             }
108             else if(fr[i][j] == 3) {
109                 scanf("%lld%lld", &val[i][j], &v2[i][j]);
110             }
111             else {
112                 scanf("%lld", &val[i][j]);
113             }
114         }
115     }
116     for(LL i = 1; i <= n; i++) {
117         for(LL j = 1; j <= n; j++) {
118             if(fr[i][j] == 0) {
119                 continue;
120             }
121             else if(fr[i][j] == 1) {
122                 scanf("%lld", &cst[i][j]);
123             }
124             else if(fr[i][j] == 2) {
125                 scanf("%lld", &c2[i][j]);
126             }
127             else if(fr[i][j] == 3) {
128                 scanf("%lld%lld", &cst[i][j], &c2[i][j]);
129             }
130             else {
131                 scanf("%lld", &cst[i][j]);
132             }
133             if(cst[i][j] == -1) {
134                 cst[i][j] = INF;
135             }
136             if(c2[i][j] == -1) {
137                 c2[i][j] = INF;
138             }
139         }
140     }
141     // read over
142     LL lm = n * m;
143     LL s = lm * 2 + 1;
144     LL t = s + 1;
145     for(LL i = 1; i <= n; i++) {
146         for(LL j = 1; j <= m; j++) {
147             if(fr[i][j] == 0) {
148                 continue;
149             }
150             if(fr[i][j] == 1 || fr[i][j] == 3) {
151                 // id(i, j)
152                 LL cnt = 0;
153                 for(LL k = i + 1; k <= n; k++) {
154                     if(fr[k][j] == 4) {
155                         cnt++;
156                     }
157                     else {
158                         break;
159                     }
160                 }
161                 // val[i][j] - cnt
162                 if(val[i][j] > cnt) {
163                     add(s, id(i, j), val[i][j] - cnt, -cst[i][j]);
164                 }
165                 add(s, id(i, j), INF, cst[i][j]);
166                 use += cst[i][j] * abs(val[i][j] - cnt);
167             }
168             if(fr[i][j] == 2 || fr[i][j] == 3) {
169                 LL cnt = 0;
170                 for(LL k = j + 1; k <= m; k++) {
171                     if(fr[i][k] == 4) {
172                         cnt++;
173                     }
174                     else {
175                         break;
176                     }
177                 }
178                 if(v2[i][j] > cnt) {
179                     add(id(i, j) + lm, t, v2[i][j] - cnt, -c2[i][j]);
180                 }
181                 add(id(i, j) + lm, t, INF, c2[i][j]);
182                 use += c2[i][j] * abs(v2[i][j] - cnt);
183             }
184             if(fr[i][j] == 4) {
185                 LL a, b;
186                 for(LL k = i - 1; k >= 1; k--) {
187                     if(fr[k][j] == 1 || fr[k][j] == 3) {
188                         a = id(k, j);
189                         break;
190                     }
191                 }
192                 for(LL k = j - 1; k >= 1; k--) {
193                     if(fr[i][k] == 2 || fr[i][k] == 3) {
194                         b = id(i, k) + lm;
195                         break;
196                     }
197                 }
198                 if(val[i][j] > 1) {
199                     add(a, b, val[i][j] - 1, -cst[i][j]);
200                 }
201                 add(a, b, INF, cst[i][j]);
202                 use += cst[i][j] * abs(val[i][j] - 1);
203             }
204         }
205     }
206 
207     LL ans;
208     solve(s, t, ans);
209     ans += use;
210 
211     /*if(ans >= INF) {
212         puts("-1");
213         return 0;
214     }*/
215     for(int i = 2; i <= top; i += 2) {
216         if(abs(edge[i].len) == INF && (edge[i].c && edge[i ^ 1].c)) {
217             puts("-1");
218             return 0;
219         }
220     }
221 
222     printf("%lld", ans);
223     return 0;
224 }
AC代码

思考:能否不转换为最小?好像无法判断是否合法...

原文地址:https://www.cnblogs.com/huyufeifei/p/10105509.html