Test Message

d373: 5. 乳酪的誘惑

內容

這個問題跟傳統的老鼠走迷宮問題不太一樣,給定一個四方形的格點空間
x 座標與 y 座標由左下角原點以 0 開始往右和往上遞增,裡面有一個區域是鼠窩,另外有一個區域是乳酪屋
此外還有很多障礙物是用來阻擋鼠輩的橫行,也就是障礙物是不可穿越的。
在此空間裡可能沒有路可以從鼠窩走到乳酪屋,此種情況你必須回報沒有路徑
如果有路可以連接鼠窩跟乳酪屋的話,你必須算出從鼠窩走到乳酪屋的最短路徑。
老鼠的每一步只能往四個方向走:上、下、左、右,不能走對角方向。出發點與終點可以是鼠窩與乳酪屋的任何一個位置。
以圖一為例,鼠窩到乳酪屋的最短距離為 15,由鼠窩裡圓圈所標示的點(10,2)往左出發走到乳酪屋中圓圈所標示的點(1,8)。
鼠窩與乳酪屋的形狀一定是一條直線,障礙物可以是一點可以是一條直線也可以是一個矩形區域
圖一中的障礙物是由三個點與兩條直線所構成,分別為點(2,6)、(3,5)、與(4,4)和線(4,3)~(7,3)與(7,4)~(7,9)。
在找尋最短路徑時,不要只派遣一隻老鼠出任務,這樣會累死這隻可憐的倒霉鼠的。

img1


輸入

輸入的第一行為兩個整數,描述方形格點空間的大小,第一個表示行的數目,第二個表示列的數目
在此問題中行和列的數目都不會超過 1000 (<=1000)。
接下來“.mb”表示後面用兩點來描述鼠窩的位置,每個點先 x 座標再 y 座標,兩個點沒有固定的先後排序。
接下來“.cb”表示後面用兩點來描述乳酪屋的位置,兩個點也沒有固定的先後排序。
最後“.bb”表示後面開始每一行描述一個障礙物的位置,不管是一點還是一條線都是用兩點來表示
最後以“.be”表示結束。

以圖一為例,其輸入檔案如下:
14 10
.mb 10 4 10 1
.cb 1 8 4 8
.bb
2 6 2 6
3 5 3 5
4 4 4 4
4 3 7 3
7 9 7 4
.be

輸出

沒有路徑的話,輸出“no path”。有路徑的話輸出最短路徑距離。

15


解題思路

強化版的尋路問題,因為可以從鼠窩的任意點出發且抵達乳酪屋的任意點及代表結束,因此將所有鼠窩的點都當作起點,使用 Dijkstra 從所有起點向外擴張,直到擴張至乳酪屋時結束。擴張的總輪數即為鼠窩移動至乳酪屋的最短距離,輸出該值即可。

  • 地圖很大,使用佇列紀錄下次擴張的位置。

  • 每個測資點僅一筆測資且鼠窩和乳酪屋皆只有一筆資料。


完整程式碼

AC (8ms, 4MB)
#include <stdio.h>
#define MAX 1010
#define SWAP(x, y) (x)^=((y)^=((x)^=(y)))

typedef struct
{
int x, y;
}Point;

Point quene1[MAX * 4], quene2[MAX * 4];
int map[MAX][MAX];
char input[100];

inline char* getUInt(register char buffer[], register unsigned int* dst)
{
while (*buffer < '0')
if (!*buffer++) return NULL;
*dst = *buffer ^ '0';
while (*++buffer >= '0')
* dst = (*dst << 3) + (*dst << 1) + (*buffer ^ '0');
return buffer;
}

inline void setMap(int map[][MAX], Point s, Point e, int val)
{
if (e.x < s.x) SWAP(e.x, s.x);
if (e.y < s.y) SWAP(e.y, s.y);
for (int i = s.x; i <= e.x; i++)
{
for (int j = s.y; j <= e.y; j++)
map[i][j] = val;
}
}

int getAns(int row, int col, register Point* nowTop)
{
Point* now = quene1, * next = quene2, * nextTop, * tmp;
for (int step = 1;; step++)
{
if (nowTop == now)
return -1;
nextTop = next;
while (now <= --nowTop)
{
if (map[nowTop->x][nowTop->y]) continue;
map[nowTop->x][nowTop->y] = step;
if (nowTop->x > 0)
{
if (map[nowTop->x - 1][nowTop->y])
{
if (map[nowTop->x - 1][nowTop->y] == -2)
return step;
}
else nextTop->x = nowTop->x - 1, nextTop++->y = nowTop->y;
}
if (nowTop->x < row)
{
if (map[nowTop->x + 1][nowTop->y])
{
if (map[nowTop->x + 1][nowTop->y] == -2)
return step;
}
else nextTop->x = nowTop->x + 1, nextTop++->y = nowTop->y;
}
if (nowTop->y > 0)
{
if (map[nowTop->x][nowTop->y - 1])
{
if (map[nowTop->x][nowTop->y - 1] == -2)
return step;
}
else nextTop->x = nowTop->x, nextTop++->y = nowTop->y - 1;
}
if (nowTop->y < col)
{
if (map[nowTop->x][nowTop->y + 1])
{
if (map[nowTop->x][nowTop->y + 1] == -2)
return step;
}
else nextTop->x = nowTop->x, nextTop++->y = nowTop->y + 1;
}
}
tmp = now, now = next, next = tmp;
nowTop = nextTop;
}
}

int main()
{
char* st;
int n, m, ans;
Point s, e, * nowTop = quene1;
scanf("%d %d", &n, &m);
scanf("%*s %d %d %d %d", &s.x, &s.y, &e.x, &e.y);
if (e.x < s.x) SWAP(e.x, s.x);
if (e.y < s.y) SWAP(e.y, s.y);
int idx = 0;
for (int i = s.x; i <= e.x; i++)
{
for (int j = s.y; j <= e.y; j++)
nowTop->x = i, nowTop++->y = j;
}
scanf("%*s %d %d %d %d %*s", &s.x, &s.y, &e.x, &e.y);
setMap(map, s, e, -2);
getchar();
while (gets(input) && input[1] != 'b')
{
st = getUInt(input, &s.x), st = getUInt(st, &s.y);
st = getUInt(st, &e.x), st = getUInt(st, &e.y);
setMap(map, s, e, -3);
}
ans = getAns(n - 1, m - 1, nowTop);
if (ans == -1)
puts("no path");
else
printf("%d", ans);
return 0;
}