(BFS+DFS)Robot Navigation

题目链接:http://www.bnuoj.com/bnuoj/problem_show.php?pid=12620

题目大意:有一个N*M大的地图,'.'表示空地,'*'表示障碍。有一个机器人,它有三种操作:

1.向前一步。

2.向左转90度。

3.向右转90度。

给出起始的位置和方向、终点的位置,机器人要从起点到达终点,求机器人在执行最少操作数的前提下,共有多少种方案数?


分析:BFS搜最少步数,DFS统计方案数。注意:起点就是终点时,方案数是1。

代码:

#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1005;
const int INF = 999999999;
#define LL long long
int M, N,mod;
int xs, ys, Dir,xe,ye;
int ans;
char a[maxn][maxn];
int dir[4][2] = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } };
bool mark[maxn][maxn][4];
int step[maxn][maxn][4];//从全局的角度记下到达每个状态的最少操作数
int num[maxn][maxn][4];//从全局的角度记下到达每个状态的在队列Q中的下标
int vis[maxn*maxn];
int head, tail;
int RES;
bool Flag;
struct NODE
{
	int x, y;
	int step;
	int dir;
	vector<int> father;
}Q[maxn*maxn*5];

int Count(int n)
{
	if (vis[n])
		return vis[n];
	if (n == 0)
		return 1;
	vis[n] = 0;
	for (int i = 0; i < Q[n].father.size(); i++)
		vis[n]=((vis[n]%mod) + Count(Q[n].father[i])%mod)%mod;

	return vis[n];
}
void Visit(NODE u,NODE v)
{
	if (mark[v.x][v.y][v.dir])
	{
		if (v.step == step[v.x][v.y][v.dir])
		{
			Q[num[v.x][v.y][v.dir]].father.push_back(num[u.x][u.y][u.dir]);

			if (v.x == xe&&v.y == ye)
			{
				RES = min(RES, v.step);
				Flag = true;

				memset(vis, false, (tail + 1)*sizeof(int));
				ans = (ans%mod + Count(num[v.x][v.y][v.dir]) % mod) % mod;
				return;
			}
		}
	}
	else
	{
		v.father.clear();	v.father.push_back(head - 1);

		mark[v.x][v.y][v.dir] = true;
		step[v.x][v.y][v.dir] = v.step;

		num[v.x][v.y][v.dir] = tail;
		if (v.x == xe&&v.y == ye)
		{
			RES = min(RES, v.step);
			Flag = true;

			memset(vis, false, (tail + 1)*sizeof(int));
			Q[tail] = v;
			ans = (ans%mod + Count(num[v.x][v.y][v.dir]) % mod) % mod;
			return;
		}
		Q[tail++] = v;
	}
}
void BFS()
{
	NODE v;
	v.x = xs;	v.y = ys;	v.step = 0;	v.father.clear();	v.dir = Dir;
	mark[v.x][v.y][v.dir] = true;	step[v.x][v.y][v.dir] = 1;
	if (v.x == xe&&v.y == ye)
	{
		Flag = true;
		ans++;
		return;
	}
	num[v.x][v.y][v.dir] = tail;
	Q[tail++] = v;
	while (head < tail)
	{
		NODE u = Q[head++];
		if (RES <= u.step)	continue;

		for (int i = 1, d = 1; i <= 2; i++, d = -d)
		{
			NODE v;
			v.x = u.x;	v.y = u.y;
			v.step = u.step + 1;
			v.dir = (u.dir + d + 4) % 4;

			Visit(u,v);
		}

		NODE v;
		v.x = u.x + dir[u.dir][0];	v.y = u.y + dir[u.dir][1];
		v.step = u.step + 1;
		v.dir = u.dir;

		if (0 <= v.x&&v.x < M && 0 <= v.y&&v.y < N)
		if (a[v.x][v.y] == '.')
			Visit(u,v);
	}
}
void solve()
{
	memset(mark, false, sizeof(mark));
	memset(step, 0, sizeof(step));
	head = tail = 0;
	ans = 0;	RES = INF;	Flag = false;

	BFS();

}
int exchange(char ch)
{
	switch (ch)
	{
	case 'N':	return 0;
	case 'E':	return 1;
	case 'S':	return 2;
	case 'W':	return 3;
	}
}
int main()
{
	//freopen("F:\\input.txt", "r", stdin);
	//freopen("F:\\test_out2.txt", "w", stdout);
	//freopen("F:\\test_in.txt", "r", stdin);
	int cas = 0;
	while (scanf("%d%d%d", &M, &N, &mod) != EOF&&mod)
	{
		getchar();
		for (int i = 0; i < M; i++)
			gets(a[i]);
		char ch;
		scanf("%d%d%d%d %c", &xs, &ys, &xe, &ye, &ch);
		Dir = exchange(ch);

		solve();

		if (!Flag)
			printf("Case %d: %d -1\n", ++cas, mod);
		else
			printf("Case %d: %d %d\n", ++cas, mod, ans);
	}
	return 0;
}

为了调试给这道题写过简陋的数据生成(有非法数据),读者可先完善一下再使用:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <time.h>
#include <algorithm>
using namespace std;
const int maxn = 1005;
const int INF = 999999999;
#define LL long long
int N, M, mod;
int xs, ys, xe, ye;
char dir;

int main()
{
	//freopen("F:\\input.txt", "r", stdin);
	freopen("F:\\test_in.txt", "w", stdout);
	//srand(NULL);
	int cas = 50;
	for (int k = 1; k <= cas; k++)
	{
		N = rand() % 10 + 1;
		M = rand() % 10 + 1;
		mod = rand() % 1000000000 + 1;
		if (k == 38 || k == 41)
			printf("%d %d %d\n", N, M, mod);
		for (int i = 1; i <= N; i++)
		{
			for (int j = 1; j <= M; j++)
			if (k == 38 || k == 41)
				printf("%c", rand() % 5 >= 3 ? '.' : '*');//'.'和'*'的生成比例为4:1
			else
				rand();
			if (k == 38 || k == 41)
				printf("\n");
		}

		xs = rand() % N;
		ys = rand() % M;
		xe = rand() % N;
		ye = rand() % M;
		int tmp = rand() % 4;
		if (tmp == 0)	dir = 'N';
		else if (tmp == 1)	dir = 'E';
		else if (tmp == 2)	dir = 'S';
		else if (tmp == 3)	dir = 'W';
		if (k == 38 || k == 41)
			printf("%d %d %d %d %c\n", xs, ys, xe, ye, dir);
	}
	printf("0 0 0\n");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值