题目链接:点击打开链接
题意:
有一个矩阵,有的地方为X,求从某一个X,所在位置为(x1, y1)到另一个X,所在位置为(x2, y2)的折线,使得线段最少,如(2, 3)到(5, 3)所连成的折线有4个线段。求最小线段数是多少。
思路:
(1)这不是单纯的求最短路问题,因为(x1, y1)到(x2, y2)的最短路径所形成的折线的线段可能大于不是最短路所形成的线段数。如
-----(x2, y2)
|
-------
|
------
|
(x1, y1)
最短路径为6,折线数是6,显然有可能存在一个折线数为2的情况。
(2)这算是BFS的另一种题型。最基础的bfs的vis数组表示当前状态是否已经访问过。这题中,某一个点可能被重复走过,能走过这个点的前提是,到这个点时,线段的数目要比之前的状态到达这个点时的数目要小。然后求一个最小值。
(3)计算转弯,可以先记录前一次相对于前一次的前一次的朝向,再计算这一次相对于前一次的朝向,判断两个朝向是否相同,不相同则线段数加1.
(4)注意样例(1, 3)到(4, 4)这里的线段已经出了边界。类似于消消看,连线可以越出边界,解决策略是把整个矩阵的横竖都扩大1,然后把矩阵挪一下位置。
(5)注意边界判断条件,注意vis数组的初始化
小结: PE了一发,忘记输出一行空行。
AC code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int MAXN = 80;
const int INF = 0x3f3f3f3f;
const int dx[4] = {0, 0, -1, 1};
const int dy[4] = {1, -1, 0, 0};
struct Node
{
int x, y, cnt, dir;
Node(int x, int y, int cnt, int dir){
this->x = x; this->y = y;
this->cnt = cnt; this->dir = dir;
}
};
int w, h, x1, y1, x2, y2;
bool tu[MAXN][MAXN];
int vis[MAXN][MAXN];
int cal(Node &t, int x, int y){
int dir = -1;
if(t.x==x){
if(t.y==y-1){
dir = 0;
}
else{
dir = 1;
}
}
else{
if(t.x==x-1){
dir = 2;
}
else{
dir = 3;
}
}
return dir;
}
int query(){
int ans = INF;
Node st(x1, y1, 0, -1);
queue<Node> q;
q.push(st);
vis[x1][y1] = 0;
while(!q.empty()){
Node tmp = q.front(); q.pop();
if(tmp.x==x2 && tmp.y==y2 && ans>tmp.cnt){
ans = tmp.cnt; continue;
}
for(int i=0; i<4; ++i){
int tx = tmp.x + dx[i];
int ty = tmp.y + dy[i];
if(tx<0||ty<0||tx>h+1||ty>w+1) continue; //judge boundary
if(tu[tx][ty]) continue; // judge whether blanket
int dir = cal(tmp, tx, ty);
int tc = (dir!=tmp.dir)?(tmp.cnt+1):tmp.cnt;
if(vis[tx][ty] < tc) continue; // judge whether smaller segment
q.push(Node(tx, ty, tc, dir));
vis[tx][ty] = tc;
}
}
return ans;
}
int main(){
char t; int cas=1;
while(true){
scanf("%d%d", &w, &h);
if(w==0&&h==0) return 0;
memset(tu, 0, sizeof(tu));
for(int i=0; i<h; ++i){
getchar();
for(int j=0; j<w; ++j){
scanf("%c", &t);
if(t=='X'){
tu[i+1][j+1] = 1;
}
}
}
int tot = 1;
printf("Board #%d:\n", cas++);
while(true){
scanf("%d%d%d%d", &y1, &x1, &y2, &x2);
if(x1==0&&y1==0&&x2==0&&y2==0) break;
memset(vis, 0x3f, sizeof(vis));
tu[x2][y2] = 0;
int ans = query();
tu[x2][y2] = 1;
if(ans==INF)
printf("Pair %d: impossible.\n", tot++);
else
printf("Pair %d: %d segments.\n", tot++, ans);
}
printf("\n");
}
return 0;
}