题解:P3208 [HNOI2010] 矩阵
xubaichuan · · 题解
这是一篇差分约束题解,代码特别简单,时间复杂度 建议加强数据,把 。
令
注意到当
故只要在
先令
::::info[感性理解]
首先,我们把
其次,
::::
根据前面的推导,
每次贪心都跑暴力做一遍差分约束,显然会 T 飞,但考虑到贪心的本质是每次增加
具体来说,我们先
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 405;
int n, m, p, a[N][N], b[N][N], s[N][N], dis[N][N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m >> p;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> s[i][j];
if (i >= 2 && j >= 2) {
b[i][j] = s[i][j] - b[i][j - 1] - b[i - 1][j] - b[i - 1][j - 1];
}
}
}
memset(dis, 0x3f, sizeof(dis));
for (int i = 1; i <= n + m; i++) {
dis[i][i] = 0;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int u = i, v = j + n;
if ((i + j) % 2) {
swap(u, v);
}
dis[u][v] = min(dis[u][v], b[i][j]); // u - v + b[i][j] >= 0
dis[v][u] = min(dis[v][u], p - 1 - b[i][j]); // u - v + b[i][j] <= p - 1
}
}
for (int k = 1; k <= n + m; k++) {
for (int i = 1; i <= n + m; i++) {
for (int j = 1; j <= n + m; j++) {
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (i >= 2 && j >= 2) {
a[i][j] = s[i][j] - a[i][j - 1] - a[i - 1][j] - a[i - 1][j - 1];
continue;
}
int u = i, v = j + n;
if ((i + j) % 2) {
swap(u, v);
}
for (int k = 0; k < p; k++) {
int w1 = k + b[i][j]; // u - v + b[i][j] >= k
int w2 = k - b[i][j]; // u - v + b[i][j] <= k
bool f = false;
for (int x = 1; x <= n + m && !f; x++) {
f = min(dis[x][u] + w1 + dis[v][x], dis[x][v] + w2 + dis[u][x]) < 0;
}
if (!f) {
a[i][j] = k;
for (int x = 1; x <= n + m; x++) {
for (int y = 1; y <= n + m; y++) {
dis[x][y] = min(dis[x][y], min(dis[x][u] + w1 + dis[v][y], dis[x][v] + w2 + dis[u][y]));
}
}
break;
}
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cout << a[i][j] << " \n"[j == m];
}
}
return 0;
}