標籤:
P1930 亞瑟王的宮殿 Camelot
-
- 題目提供者JOHNKRAM
- 標籤USACO
- 難度提高+/省選-
提交 討論 題解
最新討論
題目描述
很久以前,亞瑟王和他的騎士習慣每年元旦去慶祝他們的友誼。為了紀念上述事件, 我們把這些故事看作是一個棋盤遊戲。有一個國王和若干個騎士被放置在一個由許多方格 組成的棋盤上,沒有兩個騎士在同一個方格內。
這個例子是標準的 8*8 棋盤
國王可以移動到任何一個相鄰的方格,從中黑子位置到中白子位置前提是他 不掉出棋盤之外。
一個騎士可以從中黑子位置移動到中白子位置(走“日”字形) 但前提是他 不掉出棋盤之外。
在遊戲中,玩家可在每個方格上放不止一個棋子,假定方格足夠大,任何棋子都不會 阻礙到其他棋子正常行動。
玩家的任務就是把所有的棋子移動到同一個方格裡——用最小的步數。為了完成這個 任務,他必須按照上面所說的規則去移動棋子。另外,玩家可以選擇一個騎士跟國王從他 們兩個相遇的那個點開始一起行動,這時他們按照騎士的行動規則行動,其他的單獨騎士 則自己一直走到集中點。騎士和國王一起走的時候,只算一個人走的步數。
請計算他們集中在一起的最小步數,而且玩家必須自己找出這個集中點。當然,這些 棋子可以在棋盤的任何地方集合。
輸入輸出格式輸入格式:
第一行: 兩個用空格隔開的整數:R,C 分別為棋盤行和列的長。不超過 26 列,40 行。
第二行到結尾: 輸入檔案包含了一些有空格隔開的字母/數字對,一行有一個或以 上。第一對為國王的位置,接下來是騎士的位置。可能沒有騎士,也可能整個棋盤都是騎 士。行從 1 開始,列從大寫字母 A 開始。
輸出格式:
單獨一行表示棋子集中在一個方格的最小步數。
輸入輸出範例輸入範例#1:
8 8D 4 A 3 A 8 H 1 H 8
輸出範例#1:
10
說明
【範例說明】
他們集中在 B5。
騎士 1: A3 - B5 (1 步)
騎士 2: A8 - C7 - B5 (2 步)
騎士 3: H1 - G3 - F5 - D4 (此時國王開始與這個騎士一起走) - B5 (4 步) 騎士 4: H8 - F7 - D6 - B5 (3 步)
1 + 2 + 4 + 3 = 10 步
題目翻譯來自NOCOW。
USACO Training Section 3.3
分析:這道題是一道很明顯的搜尋題,因為集合點沒告訴,所以要枚舉集合點,這樣的話涉及到多次計算,先進行預先處理,處理每兩個點之間距離,因為是無權無向圖,用bfs就可以了,如果不考慮騎士背國王的話,只需要把所有騎士的點到集合點的距離加起來並加上國王與集合點的橫縱座標的差的最大值即可(國王可以八個方向走),如果考慮背國王的話,有點麻煩.首先你不知道是哪個騎士背國王,然後不知道在哪背,因為國王也要走動,這樣的話枚舉背的騎士和背的地點,根據之前預先處理好的數組計算即可.
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <queue>#include <cmath>using namespace std;int r, c, dis[31][27][31][27],num,ans = 100000000;const int dr[8] = { -2,-1,1,2,2,1,-1,-2 };const int dc[8] = { 1,2,2,1,-1,-2,-2,-1 };struct node{ int r, c;}king,qishi[800];bool vis[31][27];bool check(int x, int y){ if (x >= 1 && x <= r && y >= 1 && y <= c) return true; return false;}void bfs(int x,int y) { int r, c, step; queue<node> q; node temp; temp.r = x; temp.c = y; q.push(temp); memset(vis, false, sizeof(vis)); dis[x][y][x][y] = 0; vis[x][y] = true; while (!q.empty()) { node u = q.front(); q.pop(); step = dis[x][y][u.r][u.c]; for (int i = 0;i<8;++i) { int r = u.r + dr[i]; int c = u.c + dc[i]; if (check(r, c) && !vis[r][c]) { vis[r][c] = true; dis[x][y][r][c] = step + 1; node temp; temp.r = r; temp.c = c; q.push(temp); } } }}int main(){ scanf("%d%d", &r, &c); char s[3]; int t; scanf("%s %d", s, &t); king.r = t; king.c = s[0] - ‘A‘ + 1; while (scanf("%s%d", s, &t) == 2) { qishi[++num].r = t; qishi[num].c = s[0] - ‘A‘ + 1; } for (int i = 1; i <= r; i++) for (int j = 1; j <= c; j++) for (int k = 1; k <= r; k++) for (int l = 1; l <= c; l++) dis[i][j][k][l] = 1000000; for (int i = 1; i <= r; i++) for (int j = 1; j <= c; j++) bfs(i, j); for (int i = 1; i <= r; i++) for (int j = 1; j <= c; j++) { int temp = 0; for (int k = 1; k <= num; k++) temp += dis[qishi[k].r][qishi[k].c][i][j]; ans = min(ans, temp + max(abs(king.r - i), abs(king.c - j))); for (int k = 1; k <= num; k++) { int dx = qishi[k].r, dy = qishi[k].c; int t = temp - dis[dx][dy][i][j]; if (t >= ans) //最優性剪枝 continue; for (int l = 1; l <= r; l++) for (int s = 1; s <= c; s++) ans = min(ans, t + dis[l][s][dx][dy] + dis[l][s][i][j] + max(abs(king.r - l), abs(king.c - s))); } } printf("%d\n", ans); return 0;}
洛穀P1930 亞瑟王的宮殿 Camelot