算法竞赛入门经典(第二版)-刘汝佳-第七章 暴力求解法 习题(2/18)
2016-03-16 13:23
495 查看
说明
本文是我对第七章18道习题的练习总结,建议配合紫书——《算法竞赛入门经典(第2版)》阅读本文。另外为了方便做题,我在VOJ上开了一个contest,欢迎一起在上面做:第七章习题contest
如果想直接看某道题,请点开目录后点开相应的题目!!!
习题
习7-1 UVA 208 消防车
题意输入一个n(n≤20)个结点的无向图以及某个节点k,按照字典序从小到大顺序输出从节点1到节点k的所有路径,要求结点不能重复经过。
思路
这个题要事先判断节点1是否可以到达节点k,否则会超时。有很多种方法可以判断:比如DFS遍历,或者用并查集等。
然后DFS遍历即可,但考虑到算法效率,可以采取回溯+剪枝的方案(当然不剪枝也是可以AC的,时间长一点而已)。
我这个题卡在判断节点1是否可以到达节点k这一步上很久。我的代码主函数中第6行原来是:
n = 0;
后来查了很久,才发现改成
n = k;
就能AC。
按照我原来的算法逻辑,n=0的情况下,所给数据有可能出现这一种情况:
如果给出的所有路径中出现的节点都小于k,这样得到的n将小于k。
而这时候节点1肯定无法到达节点k,第一步的判断应该可以给出正确答案。
但结果就是我不改的话会WA,改了就AC。我目前从算法逻辑上仍然没有想明白。
如果有哪位大神知道,请不吝指点。
另外本题可以剪枝,可以在时间复杂度上有重大优化,请参考其他博客。
代码
[code]#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; const int N = 21; int n, k; vector<int> neigh ; int v ; int path_count; vector<int> path; bool dfs(int u) { if (u == k) return true; for (int i = 0; i < neigh[u].size(); i++) { if (!v[neigh[u][i]]) { int x = neigh[u][i]; v[x] = 1; if (dfs(x)) return true; } } return false; } void find_path() { path_count++; for (int i = 0; i < path.size(); i++) printf("%d%c", path[i], i == path.size()-1 ? '\n' : ' '); } void search(int u) { if (u == k) { find_path(); return; } for (int i = 0; i < neigh[u].size(); i++) { if (!v[neigh[u][i]]) { int x = neigh[u][i]; v[x] = 1; path.push_back(x); search(x); path.resize(path.size()-1); v[x] = 0; } } } int main() { int kase = 0; while (scanf("%d", &k) != EOF) { int a, b; int G ; memset(G, 0, sizeof(G)); n = k; while (scanf("%d%d", &a, &b), a || b) { n = max(n, max(a, b)); G[a] = G[b][a] = 1; } for (int i = 1; i <= n; i++) { neigh[i].clear(); for (int j = 1; j <= n; j++) { if (G[i][j]) neigh[i].push_back(j); } } printf("CASE %d:\n", ++kase); memset(v, 0, sizeof(v)); v[1] = 1; path_count = 0; if (dfs(1)) { path.clear(); memset(v, 0, sizeof(v)); v[1] = 1; path.push_back(1); search(1); } printf("There are %d routes from the firestation to streetcorner %d.\n", path_count, k); } return 0; }
习7-2 UVA 225 黄金图形
[b]题意平面上有k个障碍点。从(0,0)点出发,第一次走1个单位,第二次走2个单位,……,第n次走n个单位,恰好回到(0,0)。要求只能沿着东南西北方向走,且每次必须转弯90°(不能沿着同一个方向继续走,也不能后退)。走出的图形可以自交,但不能经过障碍点。
思路
首先这个题目的翻译是有问题的,漏掉了一个很重要的判断条件:每一个落脚点不能与前一个相同(出发时的原点不算)。
然后我就在不知情的情况下各种WA。后来参考了其它博客才通过的。
另外这个题我觉得条件约束给的不好,应该说清楚每个城市的坐标范围,给一个基本约束,比如说坐标范围在-100到100之间。我后来是参考其它博客定义的坐标范围。
不过,没有给坐标范围的话这个题也能做,用两个set分别存储故障点和落脚点,用于判重即可。我开始用了set,因为题意不清的原因提交后WA给改了,就成了现在的代码。
代码
[code]#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<set> using namespace std; const char tow[] = "ensw"; const int dir[4][2] = {{1, 0}, {0, 1}, {0, -1}, {-1, 0}}; typedef pair<int, int> P; int n, k; int G[250][250]; const int OFF = 105; set<P> block; int path_count; vector<int> path; void found_path() { for (int i = 0; i < path.size(); i++) printf("%c", tow[path[i]]); printf("\n"); path_count++; } void dfs(P p) { if (path.size() == n) { if (p == P(0, 0)) found_path(); return; } int m = path.size(); for (int i = 0; i < 4; i++) { if (m && (path[m-1]+1)%4/2 == (i+1)%4/2) continue; P p1 = p; bool flag = true; for (int j = 1; j <= m+1; j++) { p1.first += dir[i][0]; p1.second += dir[i][1]; int x = p1.first, y = p1.second; if (abs(x) > OFF || abs(y) > OFF || G[p1.first+OFF][p1.second+OFF] == -1) {flag = false; break;} } if (flag && G[p1.first+OFF][p1.second+OFF] != 1) { path.push_back(i); G[p1.first+OFF][p1.second+OFF] = 1; dfs(p1); G[p1.first+OFF][p1.second+OFF] = 0; path.resize(m); } } } int main() { int kase; scanf("%d", &kase); for (int t = 1; t <= kase; t++) { scanf("%d%d", &n, &k); int x, y; memset(G, 0, sizeof(G)); for (int i = 0; i < k; i++) { scanf("%d%d", &x, &y); G[x+OFF][y+OFF] = -1; } path_count = 0; path.clear(); dfs(P(0, 0)); printf("Found %d golygon(s).\n\n", path_count); } return 0; }
习7-3 UVA 211 多米诺效应
题意思路
代码
[code]
习7-4 UVA 818 切断圆环链
题意思路
代码
[code]
习7-5 UVA 690 流水线调度
题意思路
代码
[code]
习7-6 UVA 12113 重叠的正方形
题意思路
代码
[code]
习7-7 UVA 12558 埃及分数
题意思路
代码
[code]
习7-8 UVA 12107 数字谜
题意思路
代码
[code]
习7-9 UVA 1604 立体八数码问题
题意思路
代码
[code]
习7-10 UVA 11214 守卫棋盘
题意思路
代码
[code]
习7-11 UVA 12569 树上的机器人规划 (简单版)
题意思路
代码
[code]
习7-12 UVA 1533 移动小球
题意思路
代码
[code]
习7-13 UVA 817 数字表达式
题意思路
代码
[code]
习7-14 UVA 307 小木棍
题意思路
代码
[code]
习7-15 UVA 11882 最大的数
题意思路
代码
[code]
习7-16 UVA 11846 找座位
题意思路
代码
[code]
习7-17 UVA 11694 Gokigen Naname 谜题
题意思路
代码
[code]
习7-18 UVA 10384 推门游戏
题意思路
代码
[code]
相关文章推荐
- SYN2306型 北斗串口时间服务器
- NSApplicationSupportDirectory--大部分OS X应用程序注册信息的保存地
- C#动态创建类实例并动态调用指定的函数
- 好用的技术网址
- jquery validate --转载
- LeetCode#120. Triangle
- 对于求解最大公约数GCD与最小公倍数LCM的算法
- 经典排序算法(12)——总结
- C# 枚举相关操作——解析,遍历
- ScrollView嵌套Linearlayout显示不全的解决办法
- STM32_SPI多机通信的实现——整理自网络
- 线程池原理及创建(C++实现)
- opencv形状识别学习总结
- 2015-2016年全国计算机专业大学排名
- IOS系统中使用zepto的live事件绑定不了的一个办法
- android出现注: 某些输入文件使用或覆盖了已过时的 API。 注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。 注: 某些输入文件使用了未经检查或不安全的操作。 注
- Android 开发笔记
- vim默认显示行号
- sbt创建分布式spark任务
- MySQL主从复制,双机热备实战