poj3009(dfs/bfs)

题目描述:点击打开链接

/*
translation:
	题目给出冰壶初始位置,以及目标位置。要求以最短的步数将冰壶移动到目标位置。
	注意冰壶每往一个方向走上一步,就将一直往这个方向移动知道碰上障碍。碰到障碍
	时,障碍本身也被击碎。求出最短的步数是多少??

solution:
	dfs,回溯,剪枝
	要求最短路径的第一反映是用bfs,但这道题用dfs + 剪枝也能求出来。因为是求最优
	解,所以每次找到一个解时就必须对全局变量ans进行更新。所以很自然这道题便采用void
	类型的dfs。另外由于步数大于10就必须退出(因为大于10的步数在题目中是非法的),
	所以这道题用void类型的dfs就不存在死循环爆栈的问题。

note:
	1:void类型的dfs一旦处理不好边会陷入死循环导致爆栈。所以什么时候要return一定
	要处理好。此题由于步数不能大于10这个限制条件的存在,所以肯定不会死循环!
	2:冰壶移动时一定是向空位移动的,碰到障碍停下同时障碍被击碎。但是冰壶的前进方向
	的下一步是障碍时冰壶便不能往这个方向移动。
*/
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int maxn = 25;
const int INF = 1<<30;

const int E = 0;
const int S = 1;
const int W = 2;
const int N = 3;

int w, h, G[maxn][maxn];
int ans;

int dirx[] = {0, 1, 0, -1};
int diry[] = {1, 0, -1, 0};

int start_row, start_col;
int end_row, end_col;

inline bool inside(int r, int c) {
	return r >= 0 && r < h && c >= 0 && c < w;
}

void dfs(int row, int col, int cnt) {
	if(cnt > 10)	return;	//note

	int tr, tc;
	for(int d = 0; d < 4; d++) {
		tr = row;	tc = col;
		if(G[tr + dirx[d]][tc + diry[d]] == 1)	continue;	//note

		bool flag = true;
		for(;;) {
			tr += dirx[d];	tc += diry[d];
			if(!inside(tr, tc)) { flag = false; break; }
			if(G[tr][tc] == 1)	break;
			if(G[tr][tc] == 3) {
				ans = min(ans, cnt + 1);
				return;
			}
		}
		if(!flag)	continue;

		G[tr][tc] = 0;	//击碎障碍
		dfs(tr - dirx[d], tc - diry[d], cnt + 1);
		G[tr][tc] = 1;
	}

}

int main()
{
	//freopen("in.txt", "r", stdin);
    while(~scanf("%d%d", &w, &h) && w && h) {
		for(int i = 0; i < h; i++) {
			for(int j = 0; j < w; j++) {
				scanf("%d", &G[i][j]);
				if(G[i][j] == 2) {
					start_row = i;	start_col = j;
				}
				if(G[i][j] == 3) {
					end_row = i;	end_col = j;	//start position & end position
				}
			}
		}

		ans = INF;
		dfs(start_row, start_col, 0);

		if(ans > 10)	printf("-1\n");
		else			printf("%d\n", ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值