版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xMaii/article/details/75429921
题目描述
如下图所示的是一个由程序设计题目组成的ACM迷宫。迷宫的左上角是入口,右下角是出口。迷宫中每一个格子都有一个程序设计题目,挑战者要AC该题目后才能通过,大于0的数字表示AC该题目所需的最短时间。数字如果是0表示是陷阱,进去了就出不来。现在的问题是:求挑战者从入口到出口所需的最短时间。输入
有多组测试实例。
对于每组测试实例,先输入一个数字n(1< n <= 100),然后输入n*n个数字表示迷宫中的数字。输出
对应输出挑战者从入口到出口所需的最短时间。样例输入
10
1 0 2 1 2 3 4 2 2 5
2 1 0 1 3 2 5 7 2 1
1 1 1 0 1 1 1 3 2 3
1 2 1 1 0 1 1 1 2 3
1 1 2 0 2 0 2 3 2 3
2 2 2 2 3 2 0 2 3 2
3 2 2 2 1 1 1 0 1 1
0 1 1 3 0 1 1 2 3 2
2 0 1 1 2 2 2 2 2 2
3 2 3 2 3 2 3 2 3 2
5
1 2 1 2 5
1 3 2 4 5
2 1 0 2 5
2 1 1 2 1
2 4 1 1 2样例输出
min=29
min=11
这道题用dfs+剪枝求解。剪枝在三个方面:
1. 用数组vis[i][j]进行记忆化搜索,不再访问已访问过的点;
2. 如果走到终点前的任意某点时,花费的时间已经比已知的最短总时要多,则剪掉;
3. 用数组dp[x][y]来更新每次走到点(x,y)时所花费的最短时间,若此次路线来到点(x,y)花费的时间比原来的还多,那么这种方案必然不是最优;
代码如下。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXSIZE = 101;
int map[MAXSIZE][MAXSIZE], vis[MAXSIZE][MAXSIZE], dp[MAXSIZE][MAXSIZE];
int n, ans;
const int dx[] = { 0,1,-1,0 };
const int dy[] = { 1,0,0,-1 };
void init_map()
{
memset(vis, 0, sizeof(vis));
memset(dp, 0x7f, sizeof(dp)); //设为无穷大值
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
scanf("%d", &map[i][j]);
}
bool In(int x, int y) //判断点(x,y)是否合法
{
if (x<1 || x>n || y<1 | y>n)
return false;
return true;
}
void dfs(int x, int y, int time) //(x,y)是当前位置的坐标,time是已花费时间
{
if (x == n&&y == n) //到达终点
{
ans = min(time + map[x][y], ans); //更新最短时间
return;
}
if (time >= ans || time >= dp[x][y]) return; //剪枝,1.当前花费的时间已经大于最短总时;2.本次来到当前点花费的时间比原来的多
dp[x][y] = time;
for (int i = 0; i < 4; i++)
{
if (In(x + dx[i], y + dy[i]) && map[x][y] != 0 && !vis[x + dx[i]][y + dy[i]])
{
vis[x + dx[i]][y + dy[i]] = 1; //标记点(x,y)为已访问状态
dfs(x + dx[i], y + dy[i], time + map[x][y]);
vis[x + dx[i]][y + dy[i]] = 0; //还原
}
}
}
int main()
{
while (scanf("%d", &n) != EOF)
{
init_map();
ans = 0x7ffffff;
vis[1][1] = 1;
dfs(1, 1, 0);
printf("min=%d\n", ans);
}
return 0;
}