poj1101-The Game(BFS)

题目链接:点击打开链接


题意:

有一个矩阵,有的地方为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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值