POJ 3009 Curling 2.0(DFS)

Come on

今年的奥运会之后,在行星mm-21上冰壶越来越受欢迎。但是规则和我们的有点不同。这个游戏是在一个冰游戏板上玩的,上面有一个正方形网格。他们只用一块石头。游戏的目的是让石子从起点到终点,并且移动的次数最小

图1显示了一个游戏板的例子。一些正方形格子可能被砖块占据。有两个特殊的格子,起始点和目标点,这是不占用块。(这两个方块是不同的)一旦石头开始移动就不会停下,除非它击中砖块块。为了使石头到达终点,你可以通过让石块击中墙壁或者砖块来停下


图1:例子(S:开始,G:目标)

石头的运动遵循以下规则:

  • 开始时,石头静止起点广场上。
  • 石头的运动仅限于x和y方向。禁止对角线移动。
  • 当石头静止时,你可以让他向任意方向移动,除非它移动的方向上有砖块(图2(a))。
  • 一旦抛出,石头不断向同一方向移动,直到下列事件之一发生:
    • 石头击中砖块(图2(b),(c))。.
      • 石头停在他击中的砖块之前
      • 被击中的砖块消失
    • 石块飞出游戏板之外。
      • 游戏结束的条件
    • 到达目标点
      • 石头停在目标点游戏成功
  • 不能在十步之内到达目标点则返回失败。


Fig. 2: Stone movements

通过这些规则我们想知道,石头是否能够到达目标点和最少移动次数

初始配置如图1所示,石头从开始到目标需要4次移动。路线如图3所示(a)。注意当石头到达目标时,游戏版的配置如图3(b)改变。


图3:图1的解决方案和解决之后的结果。


这道题和以往的起点到终点的最短步数,有点区别;

以往的是起点到终点一个bfs就行了;这题是从起点开始每走一个方向,只有碰到障碍物或超出地图边界才会停下,因此推荐使用dfs,因为每当石头碰到障碍物的同时障碍也会消失(在搜索的时候可能有几条路,所以需要障碍物重建),要注意这点,但要是当石头停下,去搜索周围的时候,发现周围都是障碍物,则停止搜索举个栗子(偷个懒,就拿题目样例来说)

1 2 3 4 5 6(下标,初始位置为3)

1 0 2 1 1 3(往左看,有一个0,说明可以走,走到2的位置停下,1位置上的1消失)

0 0 2 1 1 3(把2看作0,往右看,可以走,走到位置3停下,位置4的1消失)

0 0 2 0 1 3(在走到位置4停下,位置5的1消失)

0 0 2 0 0 3(再走到终点)

0 0 2 0 0 3

总共4步,这是一种情况,再说另一种类似的情况

1 2 3 4 5 6(同上)

1 1 2 1 1 3(发现初始位置左右都是1,所以这种情况走不了,因此输出-1,就行)

还有一个小坑(我的小坑,wa好多次),就是题目向输入列再输入行

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 50;
int Map[maxn][maxn],vis[maxn][maxn];
int n,m,sx,sy,flag,ans;

int dr[]={1,0,-1,0};
int dc[]={0,-1,0,1};

void dfs(int x,int y,int st){
	int dx,dy,xx,yy;
	if(Map[x][y]==3){
		ans=min(ans,st);
		return;
	}
	if(st>10)return;
	for(int i=0;i<4;i++){
		dx=x+dr[i];
		dy=y+dc[i];
		xx=x;
		yy=y;
		while(dx>0&&dx<=n&&dy>0&&dy<=m&&Map[dx][dy]!=1){
			xx+=dr[i];
			yy+=dc[i];
			if(Map[xx][yy]==3){
				ans=min(ans,st);
				return;
			}
			dx=xx+dr[i];
			dy=yy+dc[i];
			if(dx<1||dx>n||dy<1||dy>m)break;
			if(Map[dx][dy]==1){
				Map[dx][dy]=0;
				dfs(xx,yy,st+1);
				Map[dx][dy]=1;
			}
		}
	}
}

int main(){
	while(~scanf("%d%d",&m,&n)&&m&&n){
		memset(Map,0,sizeof(Map));
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				scanf("%d",&Map[i][j]);
				if(Map[i][j]==2){
					sx=i;sy=j;
				}
			}
		}
		ans=401;
		dfs(sx,sy,1);
		if(ans>10)cout<<"-1"<<endl;
		else cout<<ans<<endl;
	}
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值