传送门
- 题目:
- 解题思路:
注意题里的卡片位置(x,y)对应的是(列,行),可以将坐标转换成我们熟悉的(行,列)形式。图按常规方法存,只需要将要查询的(x,y)换成(y,x)即可。
dis[x][y]表示从(x1,y1)到(x,y)所需要的最短线段数,在bfs的时候更新这个值。由于dis[x2][y2]可以由多个位置和多个方向更新来,队列中应该记录{x,y,dir,step},并且允许元素多次入队,但每个(x,y)只处理一次。
网上的博客好多都是错的,假代码没过自己的样例,但AC了。。数据挺假的,题也挺假的。😤😤😤 - ac代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define maxn 80
using namespace std;
int dx[4] = {0, 0, -1, 1};
int dy[4] = {-1, 1, 0, 0};
int h, w;
char mp[maxn][maxn];
bool vis[maxn][maxn];
int dis[maxn][maxn];
struct node {
int x, y, dir, step;
};
queue<node> q;
bool check(int x, int y)
{
if(0<=x&&x<=h+1 && 0<=y&&y<=w+1 && !vis[x][y] && mp[x][y]==' ') return true;
return false;
}
bool bfs(int x1, int y1, int x2, int y2)
{
memset(vis, false, sizeof(vis));
fill(dis[0], dis[0]+maxn*maxn, 9999999);
while(!q.empty()) q.pop();
bool flag = false;
q.push({x1, y1, -1, 0});
while(!q.empty())
{
node no = q.front(); q.pop();
int x = no.x, y = no.y, dir = no.dir, step = no.step;
if(x==x2 && y==y2) { flag = true; continue; }
if(vis[x][y]) continue;
vis[x][y] = true;
for(int i = 0; i <= 3; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if(check(nx, ny))
{
int nstep = step;
if(i!=dir) nstep++;
q.push({nx, ny, i, nstep});
dis[nx][ny] = min(dis[nx][ny], nstep);
}
}
}
return flag;
}
int main()
{
int cnt1 = 0, cnt2 = 0;
int x1, y1, x2, y2;
while(scanf("%d %d", &w, &h)==2 && w&&h)
{
memset(mp, ' ', sizeof mp);
getchar();
for(int i = 1; i <= h; i++)
{
for(int j = 1; j <= w; j++) mp[i][j] = getchar();
getchar();
}
printf("Board #%d:\n", ++cnt1);
cnt2 = 0;
while(scanf("%d %d %d %d", &x1, &y1, &x2, &y2)==4 && x1&&y1&&x2&&y2)
{
swap(x1, y1); swap(x2, y2);
mp[x2][y2]=' ';
if(bfs(x1, y1, x2, y2)) printf("Pair %d: %d segments.\n", ++cnt2, dis[x2][y2]);
else printf("Pair %d: impossible.\n", ++cnt2);
mp[x2][y2]='X';
}
printf("\n");
}
return 0;
}