P1930 [USACO3.3] 亚瑟王的宫殿
这篇题解里有这样一段话:
- 那这题是不是没做头了?
题当然还是可以做,你可以枚举棋盘上每一个点来判断是否为王与骑士相遇点,然后暴力枚举骑士,再暴力枚举集合点,最劣是
O(R^3*C^3) ,但是不可能达到这么大。
但是实际上没有
先考虑对角线的情况,图中红点是国王,黄点是骑士,绿色箭头是骑士的移动路线。
这段路线骑士走会产生
手玩一下这幅图(也可以写暴力来验证),可以得出结论:如果上车点在黄色点上,那么就一定会让国王走到上车点。
所以只需要把 复制借鉴一下,把贪心范围加上国王所处的两条对角线就可以了。
最后时间复杂度为
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
struct node {
int x, y;
int d;
} pe[2010];
int r, c, dx[] = {1, 2, 2, 1, -1, -2, -2, -1}, dy[] = {2, 1, -1, -2, -2, -1, 1, 2}, cnt;
bool v[50][30];
int ans = 1145141919810ll, d[50][30][50][30];
void bfs(int a, int b) {
queue<node> q;
q.push({a, b, 0});
v[a][b] = 1;
d[a][b][a][b] = 0;
while (!q.empty()) {
int x = q.front().x, y = q.front().y;
d[a][b][x][y] = q.front().d;
q.pop();
for (int i = 0; i < 8; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (nx >= 1 && nx <= r && ny >= 1 && ny <= c && !v[nx][ny]) {
v[nx][ny] = 1;
q.push({nx, ny, d[a][b][x][y] + 1});
}
}
}
}
signed main() {
cin >> r >> c;
for (int i = 0; i <= r + 1; i++) {
for (int j = 0; j <= c + 1; j++) {
for (int a = 0; a <= r + 1; a++) {
for (int b = 0; b <= c + 1; b++) {
d[i][j][a][b] = 2e8;
}
}
}
}
char t1;
int t2;
while (cin >> t1 >> t2) {
pe[cnt].x = t2;
pe[cnt].y = t1 - 'A' + 1;
cnt++;
}
cnt--;
for (int i = 1; i <= r; i++) {
for (int j = 1; j <= c; j++) {
memset(v, 0, sizeof(v));
bfs(i, j);
}
}
for (int i = 1; i <= r; i++) {
for (int j = 1; j <= c; j++) {
int g = 0;
for (int k = 1; k <= cnt; k++) {
g += d[pe[k].x][pe[k].y][i][j];
}
ans = min(g + max(abs(pe[0].x - i), abs(pe[0].y - j)), ans);
for (int k = 1; k <= cnt; k++) {
int temp = g - d[pe[k].x][pe[k].y][i][j];
for (int a = max(1ll, pe[0].x - 2); a <= min(r, pe[0].x + 2); a++) {
for (int b = max(1ll, pe[0].y - 2); b <= min(c, pe[0].y + 2); b++) {
ans = min(temp + d[pe[k].x][pe[k].y][a][b] + max(abs(a - pe[0].x), abs(b - pe[0].y)) + d[a][b][i][j], ans);
}
}
int a = pe[0].x, b = pe[0].y;
while (a > 0 && b > 0) {
a--;
b--;
ans = min(temp + d[pe[k].x][pe[k].y][a][b] + max(abs(a - pe[0].x), abs(b - pe[0].y)) + d[a][b][i][j], ans);
}
a = pe[0].x, b = pe[0].y;
while (a > 0 && b <= c) {
a--;
b++;
ans = min(temp + d[pe[k].x][pe[k].y][a][b] + max(abs(a - pe[0].x), abs(b - pe[0].y)) + d[a][b][i][j], ans);
}
a = pe[0].x, b = pe[0].y;
while (a <= r && b > 0) {
a++;
b--;
ans = min(temp + d[pe[k].x][pe[k].y][a][b] + max(abs(a - pe[0].x), abs(b - pe[0].y)) + d[a][b][i][j], ans);
}
a = pe[0].x, b = pe[0].y;
while (a <= r && b <= c) {
a++;
b++;
ans = min(temp + d[pe[k].x][pe[k].y][a][b] + max(abs(a - pe[0].x), abs(b - pe[0].y)) + d[a][b][i][j], ans);
}
}
}
}
cout << ans << endl;
return 0;
}