您的位置:首页 > 其它

sdutoj 1157 小鼠迷宫问题

2013-10-03 18:27 387 查看
题目链接:  sdutoj 1157 小鼠迷宫问题

/*
* 作者 仪冰
* QQ 974817955
* 题目 sdutoj 1157 小鼠迷宫问题

【题目描述】
小鼠a与小鼠b身处一个m×n的迷宫中,如图所示。每一个方格表示迷宫中的一个房间。这m×n个房间中有一些房间是封闭的,不允许任何人进入。在迷宫中任何位置均可沿上,下,左,右4个方向进入未封闭的房间。小鼠a位于迷宫的(p,q)方格中,它必须找出一条通向小鼠b所在的(r,s)方格的路。请帮助小鼠a找出所有通向小鼠b的最短道路。

【输入】
本题有多组输入数据,你必须处理到EOF为止。
每组数据的第一行有3个正整数n,m,k,分别表示迷宫的行数,列数和封闭的房间数。
接下来的k行中,每行2个正整数,表示被封闭的房间所在的行号和列号。
最后的2行,每行也有2个正整数,分别表示小鼠a所处的方格(p,q)和小鼠b所处的方格(r,s)。

【输出】
对于每组数据,将计算出的小鼠a通向小鼠b的最短路长度和有多少条不同的最短路输出。
每组数据输出两行,第一行是最短路长度;第2行是不同的最短路数。
每组输出之间没有空行。
如果小鼠a无法通向小鼠b则输出“No Solution!”。

【示例输入】
8 8 3
3 3
4 5
6 6
2 1
7 7
【示例输出】
11
96

【思路】 用BFS求最短路径长度;用DFS求最短路径条数。
DFS时,用到奇偶性剪枝,剪枝很重要。
*/

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>

using namespace std;

const int SIZE = 102;

//边界数组,四个方向,按照下、右、上、左的顺序
int coordinate[4][2] = {1,0, 0,1, -1,0, 0,-1};

int mazeBfs[SIZE][SIZE];  //广搜用的迷宫
int mazeDfs[SIZE][SIZE];  //深搜用的迷宫

int oddEven[SIZE][SIZE];  //奇偶剪枝状态数组

int n;  //迷宫行数
int m;  //迷宫列数
int k;  //封闭房间数
int kr, kl; //每个封闭房间的行号和列号
int p, q;  //小鼠a的行号和列号
int r, s;  //小鼠b的行号和列号
int ShortestPathLength; //最短路径的长度
int ShortestPahtNumber; //最短路径的条数

//广搜求最短路径长度
//int BFS(int p, int q, int r, int s, int len, int n, int m);
int BFS();

//深搜求最短路径条数
//void DFS(int x, int y, int r, int s, int len, int n, int m, int shortlength);
void DFS(int x, int y, int
4000
len);

int main()
{
while (scanf("%d%d%d", &n, &m, &k) != EOF)
{
memset(mazeBfs, 0, sizeof(mazeBfs));  //初始化迷宫
memset(mazeDfs, 0, sizeof(mazeDfs));

//奇偶剪枝数组初始化
for (int i=0; i<=n; i++)
{
if (i%2 == 1)
{
for (int j=0; j<=m; j++)
{
if (j%2 == 1)
{
oddEven[i][j] = 1;
}
else
{
oddEven[i][j] = 0;
}
}
}
else
{
for (int j=0; j<=m; j++)
{
if (j%2 == 1)
{
oddEven[i][j] = 0;
}
else
{
oddEven[i][j] = 1;
}
}

}
}

for (int i=1; i<=k; i++)
{
scanf("%d%d", &kr, &kl);  //输入封闭房间的坐标

//存入迷宫中,迷宫中,1代表封闭房间,0代表可以走
mazeBfs[kr][kl] = 1;
mazeDfs[kr][kl] = 1;
}

scanf("%d%d", &p, &q);  //小鼠a的坐标
scanf("%d%d", &r, &s);  //小鼠b的坐标

//求最短路径长度
ShortestPathLength = BFS();
if (ShortestPathLength == -1) //没路可走时
{
printf("No Solution!\n");
continue;
}

//求最短路径条数
ShortestPahtNumber = 0;
DFS(p, q, 0);

//输出结果
printf("%d\n%d\n", ShortestPathLength, ShortestPahtNumber);
}

return 0;
}

int BFS()
{
queue<int> qx;  //存横坐标的队列
queue<int> qy;  //存纵坐标的队列
queue<int> qlen;  //存长度的队列
int xa, ya; //当前节点坐标
int length; //到达当前节点长度

qx.push(p);
qy.push(q);
qlen.push(0);

mazeBfs[p][q] = 1;

while (!qx.empty())
{
if ((qx.front()==r) && (qy.front()==s)) //判断是否到达小鼠b
{
return qlen.front();
}

//临时保存队头值
int xx, yy ,ll;
xx = qx.front();
yy = qy.front();
ll = qlen.front();

//保存完之后,出队
qx.pop();
qy.pop();
qlen.pop();

for (int i=0; i<4; i++)
{
//算第i方向上的新值
xa = xx + coordinate[i][0];
ya = yy + coordinate[i][1];
length = ll;

//新的点在迷宫内,且没有走过
if ((xa>=1) && (xa<=n) && (ya>=1) && (ya<=m) && (mazeBfs[xa][ya]==0))
{
//入队
qx.push(xa);
qy.push(ya);
length += 1;
qlen.push(length);

//标记新点
mazeBfs[xa][ya] = 1;
}
}
}

return -1;  //如果没有路,返回0
}

void DFS(int x, int y, int len)
{
if ((x==r) && (y==s) && (len==ShortestPathLength))  //找到一条最短路径
{
ShortestPahtNumber++;
return ;
}

//一般剪枝
int theoryShortestLength; //当前节点到终点的理论最小值
theoryShortestLength = (abs(x-r)) + (abs(y-s));
if ((len+theoryShortestLength) > ShortestPathLength) //当前长度+理论最小值>最短路径长度
{
return ;
}

//奇偶剪枝
if ((ShortestPathLength-len)%2 != ((abs(oddEven[x][y]-oddEven[r][s])) % 2))
{
return ;
}

for (int i=0; i<4; i++)
{
int xx, yy;
xx = x + coordinate[i][0];
yy = y + coordinate[i][1];

if ((xx>=1) && (xx<=n) && (yy>=1) && (yy<=m) && (mazeDfs[xx][yy]==0))
{
mazeDfs[xx][yy] = 1;
DFS(xx, yy, len+1);

//回溯
mazeDfs[xx][yy] = 0;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: