POJ 3009 Curling 2.0(深度优先搜索+剪枝)

106 篇文章 0 订阅
34 篇文章 0 订阅

题意:

给一个图,由障碍和空地组成,一块石头可以在上面往一个方向滑动,只能沿着x,y方向滑动,并且那个方向上第一个地方不能是障碍物,石头滑动直到碰到障碍停止,并且消掉障碍物,或者滑出边界,这时候算游戏失败,给出起点和终点,问石头能否在十步之内到达终点,能的话最小步数是多少.


思路:


题目很简单,只需要模拟dfs就可以,注意走过的点可以重新走,因为图是在变化的,建图的时候可以全部初始化为-1,这样判断边界比较简单.但是只是模拟的话会超时,这时候需要剪枝,题目让求最小不熟,可以设定一个变量记录当前最小步数,初始化为11(因为题目要求10步及以内),若dfs时步数大于当前最小步数则退出,可以省去很多不必要的搜索.


代码:


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[25][25];
int n, m;
int mi;
int gx, gy;
int next[4][2] = {{1, 0}, {0, 1}, {0, -1}, { -1, 0}};
void dfs(int x, int y, int step)
{
	int i;
	if(step>mi)return;  //如果当前搜索步数大于当前最小步数了, 就不必要搜索.
	for (i = 0; i < 4; i++)
	{
		int nx, ny;
		nx = x + next[i][0];
		ny = y + next[i][1];
	    while (a[nx][ny] != -1 && a[nx][ny] != 1) //判断第一个地方是否是边界或障碍
		{
			if (a[nx][ny] == 3)
			{
				if (step < mi)
				{
					mi = step;
				}
				break;
			}
			nx += next[i][0];
			ny += next[i][1];
			if (a[nx][ny] != 0)
			{
				if (a[nx][ny] == -1)
				{
					break;
				}
				if (a[nx][ny] == 1)
				{
					a[nx][ny] = 0;
					nx -= next[i][0];
					ny -= next[i][1];
					dfs(nx, ny, step + 1);
					nx += next[i][0];
					ny += next[i][1];
					a[nx][ny] = 1;  //还原图,因为接下来的操作和这一步是并列的,互不影响.
					break;
				}
				if (a[nx][ny] == 3)
				{
					if (step < mi)
					{
						mi = step;
					}
					return;
				}

			}
		}
	}
	return;
}
int main()
{
	while (~scanf("%d%d", &m, &n))
	{
		if (n == m && n == 0)
		{
			break;
		}
		memset(a, -1, sizeof(a));  //初始化-1,建图之后-1的地方自然就是边界
		memset(book, 0, sizeof(book));
		int i, j;
		mi = 11; //初始化
		int sx, sy;
		for (i = 1; i <= n; i++)
		{
			for (j = 1; j <= m; j++)
			{
				scanf("%d", &a[i][j]);
				if (a[i][j] == 2)
				{
					sx = i;
					sy = j;
				}
				if (a[i][j] == 3)
				{
					gx = i;
					gy = j;
				}
			}
		}
		dfs(sx, sy, 1);
		if (mi <= 10)
		{
			printf("%d\n", mi);
		}
		else
		{
			printf("-1\n");
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值