nyoj-306-走迷宫--二分法+dfs
2015-08-21 14:28
393 查看
nyoj-306-走迷宫–二分法+dfs
题目 走迷宫
限制
1000ms | 65535kb描述
Dr.Kong设计的机器人卡多非常爱玩,它常常偷偷跑出实验室,在某个游乐场玩之不疲。这天卡多又跑出来了,在SJTL游乐场玩个不停,坐完碰碰车,又玩滑滑梯,这时卡多又走入一个迷宫。整个迷宫是用一个N * N的方阵给出,方阵中单元格中填充了一个整数,表示走到这个位置的难度。这个迷宫可以向上走,向下走,向右走,向左走,但是不能穿越对角线。走迷宫的取胜规则很有意思,看谁能更快地找到一条路径,其路径上单元格最大难度值与最小难度值之差是最小的。当然了,或许这样的路径不是最短路径。
机器人卡多现在在迷宫的左上角(第一行,第一列)而出口在迷宫的右下角(第N行,第N列)。
卡多很聪明,很快就找到了这样的一条路径。你能找到吗?
输入
有多组测试数据,以EOF为输入结束的标志第一行: N 表示迷宫是N*N方阵 (2≤ N≤ 100)
接下来有N行, 每一行包含N个整数,用来表示每个单元格中难度 (0≤任意难度≤120)。
输出
输出为一个整数,表示路径上最高难度与和最低难度的差。样例输入
5 1 1 3 6 8 1 2 2 5 5 4 4 0 3 3 8 0 2 3 4 4 3 0 2 1
样例输出
2
分析
题意是要为仅能上、下、左、右行动的机器找出一条从左上角到右下角的路径,并且这条路径上的最大值和最小值之差要最小。看到题目,先是用dfs直接实现,果不其然TLE。又是看了几遍题目后发现,难度的区间已给出:[0, 120],若用二分的话感觉会优化不少时间,但是应该也要几百ms。以防万一我去查了一下其他人的运行时间发现大都只有不到100ms,以为算法错了。浪费了好多时间和本来就不多的脑细胞,实在想不出其他较好的方法,就上网查了一下,发现竟然都是二分+dfs,于是敲码后提交,果然只有16ms…
可能本题的数据比较水,但还是应该“实践出真知”
二分法需要细心设计一下,附上代码:
/* * nyoj. 306 * date: 2015.8.21 * 16sm 656kb */ #include <iostream> #include <cstdio> #include <memory.h> #define max(a,b) a>b ? a : b #define min(a,b) a<b ? a : b using namespace std; const int INF = 100000000; const int MAXL = 110; const int direction[4][2] = {1, 0, -1, 0, 0, 1, 0, -1}; int arr[MAXL][MAXL], visited[MAXL][MAXL]; int N , tempmindif, tempmaxdif // 当前根据二分法确定的最小值、最 , mindif, maxdif; // 大值整个输入的最小值、最大值 bool inscale(int x, int y) { // 判断点坐标(x, y)是否在当前确定的最大值、最小值之间 return arr[x][y] >= tempmindif && arr[x][y] <= tempmaxdif; } bool dfs(int x, int y) { if (x == N && y == N) return true; int nearx, neary; for (int i = 0; i < 4; ++i) { nearx = x + direction[i][0]; neary = y + direction[i][1]; if (!visited[nearx][neary] && inscale(nearx, neary)) { visited[nearx][neary] = true; if (dfs(nearx, neary)) return true; } } return false; } bool findpath(int key) { for (int i = mindif; i <= maxdif - key; ++i) { tempmindif = i, tempmaxdif = i+key; if (!inscale(1, 1) || !inscale(N, N)) // 如果起始点或终止点不在当前最小值、最大值之 continue; // 间,那这个当前最小值、最大值肯定是错误的 memset(visited, false, sizeof(visited)); visited[1][1] = true; if (dfs(1, 1)) return true; } return false; } int main() { memset(arr, -1, sizeof(arr)); //赋值成-1,可省去dfs时边界的判定 while (~scanf("%d", &N)) { mindif = INF, maxdif = 0; for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { scanf("%d", *(arr+i)+j); maxdif = max(maxdif, arr[i][j]); mindif = min(mindif, arr[i][j]); } } int bsmid, bsleft = 0, bsright = maxdif - mindif; while (bsleft <= bsright) { //二分法的设计需要仔细考虑 bsmid = (bsleft + bsright) >> 1; if (findpath(bsmid)) bsright = bsmid - 1; else bsleft = bsmid + 1; } printf("%d\n", bsleft); } return 0; }
相关文章推荐
- php二分法在IP地址查询中的应用
- Python实现二分法算法实例
- Python二分法搜索算法实例分析
- 八大方法巧妙排除网络连接故障
- linux kernel data struct: binary search
- HDU 2199
- 数值计算库中使用设计模式(一)
- leetcode:Find Peak Elements 菜鸟解法
- leetcode:Find Minimum in Rotated Sorted Array II 菜鸟解法
- leetcode:Find Minimum in Rotated Sorted Array 菜鸟解法
- leetcode:Search Insert Position菜鸟解法
- 第一次周赛C
- poj 3273
- hdu 1969
- 第三周—二分法4 已知面积,求最大体积
- 第三周练习题目—二分法 影子的最大长度
- 第三周练习——二分法2 方程求解
- C二分法查找
- 二分法查找,插入法查找及冒泡排序的改进
- Java 编程下的二分法查找