一、題目鏈接
二、思路
本題的路線可延伸到矩形板的外面,延伸多遠都沒關係。但是因爲題目要求的是最小的線段數量,則伸出一個格子跟伸出多個格子沒有區別。爲了簡單起見,伸出一個格子就好。這樣就可以把原來的矩形板的面積增加一圈,即列從[1, w]擴大爲[0, w+1],行從[1, h]擴大爲[0, h+1]。
本題可使用廣度優先搜索來解決。每個head格子出隊後,周圍最多有四個不同方向的相鄰格子可入隊。當某個方向的相鄰格子入隊後,優先往這個方向一直前進,在這個過程中不需要拐彎,經過的格子也不需要入隊,因爲入隊會導致拐彎次數增加。
三、代碼
#include <iostream>
#include <cstdio>
#include <queue>
#include <memory.h>
using namespace std;
struct grid
{
int x; //本題中x爲列
int y; //y爲行
int step; //第幾條線段,即變了幾次方向
};
int dx[]={0, 0, 0, -1, 1};//移動列
int dy[]={0, -1, 1, 0, 0};//移動行
int sx, sy, ex, ey, w, h;
const int maxN = 80;
char Map[maxN][maxN];
bool vis[maxN][maxN];
bool check(int x, int y)
{
//因爲可跑到矩形板的外面,所以四個邊界都要加1
if(x >= 0 && x <= w+1 && y >= 0 && y <= h+1 && !vis[x][y])
{
if(Map[x][y] == ' ' || (Map[x][y] == 'X' && x == ex && y == ey))
{
return true;
}
return false;
}
return false;
}
queue<grid>q;
void bfs()
{
grid start;
start.x = sx;
start.y = sy;
start.step = 0;
vis[sx][sy] = true;
q.push(start);
while(!q.empty())
{
grid head = q.front();
q.pop();
grid Next; //相鄰的四個格子
for(int i=1; i<=4; i++)
{
Next.x = head.x + dx[i];
Next.y = head.y + dy[i];
Next.step = head.step + 1; //每換個方向,線段數就會加1,所以step加1
while(check(Next.x, Next.y))
{
if(Next.x == ex && Next.y == ey)
{
printf("%d segments.\n", Next.step);
return;
}
vis[Next.x][Next.y] = true;
q.push(Next);
//往dx[i],dy[i]這個固定的方向一直前進,不會引起線段數量增加,所以step不加1
//處於固定方向一直前進中途上的各個點,不需要進隊列,因爲進隊列就意味着可調方向,
//調方向得到的線段數必然多於不調方向得到的線段樹。
Next.x += dx[i];
Next.y += dy[i];
}
}
}
printf("impossible.\n");
return;
}
int main()
{
//freopen("game.in", "r", stdin);
int cnt=0;
while(true)
{
cnt++;
scanf("%d%d", &w, &h); //寬(列)和高(行)
if(w==0 && h==0)
{
break;
}
memset(Map, ' ', sizeof(Map));
getchar(); //吸收換行符
for(int r = 1; r <= h; r++) //行
{
string str;
getline(cin, str);
for (int c = 1; c <= w; c++)//列
{
Map[c][r] = str[c - 1];
}
}
printf("Board #%d:\n", cnt);
int pairCnt = 0;
while(true)
{
pairCnt++;
scanf("%d%d%d%d", &sx, &sy, &ex, &ey);
if(sx==0 && sy==0 && ex==0 && ey==0)
{
break;
}
printf("Pair %d: ", pairCnt);
memset(vis, false, sizeof(vis));
bfs();
//注意queue沒有clear()函數,要清空得逐個彈出
while(!q.empty())
{
q.pop();
}
}
printf("\n");
}
return 0;
}
瞭解信息學奧賽請加微信307591841(QQ同號)