题目链接: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");
}