基础搜索算法题解(D-H)
来源:互联网 发布:程序员算法题 编辑:程序博客网 时间:2024/05/29 16:25
练习链接:http://acm.njupt.edu.cn/vjudge/contest/view.action?cid=171#overview
D题 A Knight's Journey
Memory Limit: 65536KTotal Submissions: 32388
Accepted: 11027
Description
The knight is getting bored of seeing the same black and white squares again and again and has decided to make a journey
around the world. Whenever a knight moves, it is two squares in one direction and one square perpendicular to this. The world of a knight is the chessboard he is living on. Our knight lives on a chessboard that has a smaller area than a regular 8 * 8 board, but it is still rectangular. Can you help this adventurous knight to make travel plans?
Problem
Find a path such that the knight visits every square once. The knight can start and end on any square of the board.
Input
Output
If no such path exist, you should output impossible on a single line.
Sample Input
31 12 34 3
Sample Output
Scenario #1:A1Scenario #2:impossibleScenario #3:A1B3C1A2B4C2A3B1C3A4B2C4
Source
题目链接:http://poj.org/problem?id=2488
题目大意:给一个p*q的棋盘,行用数字表示,列用字母表示,求用马步遍历的遍历序列,马走“日”。
题目分析:没啥好说的,裸DFS,因为题目说了从任意一点开始都可以,说明解是一个圈,所以当然从A1开始搜字典序最小了,方向遍历时也要根据字典序来遍历,关键是记录路径,和k题类似,二维数组,一维用深度来记录路径
#include <cstdio>#include <cstring>int vis[30][30];int path[30][2];int p,q;bool flag;int dirx[8] = {-1,1,-2,2,-2,2,-1,1};int diry[8] = {-2,-2,-1,-1,1,1,2,2};void DFS(int x,int y, int step){ path[step][0] = x; path[step][1] = y; if(step == p * q) { flag = true; return; } for(int i = 0; i < 8; i++) { int xx = x + dirx[i]; int yy = y + diry[i]; if(xx < 1 || yy < 1 || xx > p || yy > q || vis[xx][yy] || flag) continue; vis[xx][yy] = 1; DFS(xx, yy, step + 1); vis[xx][yy] = 0; }}int main(){ int T; scanf("%d",&T); for(int i = 1; i <= T; i++) { scanf("%d %d",&p, &q); memset(vis, 0, sizeof(vis)); vis[1][1] = 1; flag = false; DFS(1, 1, 1); if(flag) { printf("Scenario #%d:\n",i); for(int i = 1; i <= p * q; i++) printf("%c%d", path[i][1] - 1 + 'A', path[i][0]); printf("\n"); } else printf("Scenario #%d:\nimpossible\n",i); if(i != T) printf("\n"); }}
E题 Children of the Candy Corn
Time Limit: 1000MSMemory Limit: 65536KTotal Submissions: 10145
Accepted: 4405
Description
One popular maze-walking strategy guarantees that the visitor will eventually find the exit. Simply choose either the right or left wall, and follow it. Of course, there's no guarantee which strategy (left or right) will be better, and the path taken is seldom the most efficient. (It also doesn't work on mazes with exits that are not on the edge; those types of mazes are not represented in this problem.)
As the proprieter of a cornfield that is about to be converted into a maze, you'd like to have a computer program that can determine the left and right-hand paths along with the shortest path so that you can figure out which layout has the best chance of confounding visitors.
Input
Exactly one 'S' and one 'E' will be present in the maze, and they will always be located along one of the maze edges and never in a corner. The maze will be fully enclosed by walls ('#'), with the only openings being the 'S' and 'E'. The 'S' and 'E' will also be separated by at least one wall ('#').
You may assume that the maze exit is always reachable from the start point.
Output
Sample Input
28 8#########......##.####.##.####.##.####.##.####.##...#..##S#E####9 5##########.#.#.#.#S.......E#.#.#.#.##########
Sample Output
37 5 517 17 9
Source
题目链接:http://poj.org/problem?id=3083
题目大意:一个m*n的矩阵给出起点和终点求两点间左优先路,右优先路和最短路
题目分析:最短显然用BFS裸的,左右优先用DFS做,这题就是代码量大的水题
#include <cstdio>#include <queue>#include <cstring>using namespace std;int n, m;int sx, sy, ex, ey;char map[42][42];bool vis[42][42];int dx[] = {1, 0, -1, 0}; //方向不能反!int dy[] = {0, 1, 0, -1};struct Node{ int x, y; int step;};queue <Node> q;bool flag;int l, r; //记录左优先和右优先的解int BFS() //求最短{ memset(vis, 0, sizeof(vis)); Node t, cur, st; st.x = sx; st.y = sy; vis[sx][sy] = true; st.step = 1; q.push(st); while(!q.empty()) { cur = q.front(); q.pop(); if(cur.x == ex && cur.y == ey) { while(!q.empty()) q.pop(); return cur.step; } for(int i = 0; i < 4; i++) { t.x = cur.x + dx[i]; t.y = cur.y + dy[i]; t.step = cur.step + 1; if(t.x < n && t.y < m && t.x >= 0 && t.y >= 0 && !vis[t.x][t.y] && map[t.x][t.y] != '#') { vis[t.x][t.y] = true; q.push(t); } } } return 0;}int DFS(int x, int y, int dir){ if(x == ex && y == ey) return 1; for(int i = 0; i < 4; i++) { int xx = x + dx[dir]; int yy = y + dy[dir]; if(map[xx][yy] == '.' || map[xx][yy] == 'E') { if(flag) { l++; if(dir == 3) dir = -1; if(DFS(xx, yy, dir + 1)) return 1; } else { r++; if(dir == 0) dir = 4; if(DFS(xx, yy, dir - 1)) return 1; } } if(flag) { dir--; if(dir == -1) dir = 3; } else { dir++; if(dir == 4) dir = 0; } } return 0;}int main(){ int T; scanf("%d", &T); while(T--) { scanf("%d %d", &m, &n); for(int i = 0; i < n; i++) { scanf("%s", map[i]); for(int j = 0; j < m; j++) { if(map[i][j] == 'S') { sx = i; sy = j; } if(map[i][j] == 'E') { ex = i; ey = j; } } } flag = true; l = r = 1; DFS(sx, sy, 0); flag = false; DFS(sx, sy, 0); printf("%d %d %d\n", l, r, BFS()); }}
F题 Curling 2.0
Description
On Planet MM-21, after their Olympic games this year, curling is getting popular. But the rules are somewhat different from ours. The game is played on an ice game board on which a square mesh is marked. They use only a single stone. The purpose of the game is to lead the stone from the start to the goal with the minimum number of moves.
Fig. 1 shows an example of a game board. Some squares may be occupied with blocks. There are two special squares namely the start and the goal, which are not occupied with blocks. (These two squares are distinct.) Once the stone begins to move, it will proceed until it hits a block. In order to bring the stone to the goal, you may have to stop the stone by hitting it against a block, and throw again.
Fig. 1: Example of board (S: start, G: goal)
The movement of the stone obeys the following rules:
- At the beginning, the stone stands still at the start square.
- The movements of the stone are restricted to x and y directions. Diagonal moves are prohibited.
- When the stone stands still, you can make it moving by throwing it. You may throw it to any direction unless it is blocked immediately(Fig. 2(a)).
- Once thrown, the stone keeps moving to the same direction until one of the following occurs:
- The stone hits a block (Fig. 2(b), (c)).
- The stone stops at the square next to the block it hit.
- The block disappears.
- The stone gets out of the board.
- The game ends in failure.
- The stone reaches the goal square.
- The stone stops there and the game ends in success.
- The stone hits a block (Fig. 2(b), (c)).
- You cannot throw the stone more than 10 times in a game. If the stone does not reach the goal in 10 moves, the game ends in failure.
Fig. 2: Stone movements
Under the rules, we would like to know whether the stone at the start can reach the goal and, if yes, the minimum number of moves required.
With the initial configuration shown in Fig. 1, 4 moves are required to bring the stone from the start to the goal. The route is shown in Fig. 3(a). Notice when the stone reaches the goal, the board configuration has changed as in Fig. 3(b).
Fig. 3: The solution for Fig. D-1 and the final board configuration
Input
The input is a sequence of datasets. The end of the input is indicated by a line containing two zeros separated by a space. The number of datasets never exceeds 100.
Each dataset is formatted as follows.
the width(=w) and the height(=h) of the board
First row of the board
...
h-th row of the board
The width and the height of the board satisfy: 2 <=w <= 20, 1 <=h <= 20.
Each line consists of w decimal numbers delimited by a space. The number describes the status of the corresponding square.
0 vacant square1 block2 start position3 goal position
The dataset for Fig. D-1 is as follows:
6 6
1 0 0 2 1 0
1 1 0 0 0 0
0 0 0 0 0 3
0 0 0 0 0 0
1 0 0 0 0 1
0 1 1 1 1 1
Output
For each dataset, print a line having a decimal integer indicating the minimum number of moves along a route from the start to the goal. If there are no such routes, print -1 instead. Each line should not have any character other than this number.
Sample Input
2 13 26 61 0 0 2 1 01 1 0 0 0 00 0 0 0 0 30 0 0 0 0 01 0 0 0 0 10 1 1 1 1 16 11 1 2 1 1 36 11 0 2 1 1 312 12 0 1 1 1 1 1 1 1 1 1 313 12 0 1 1 1 1 1 1 1 1 1 1 30 0
Sample Output
14-1410-1
Source
题目链接:http://poj.org/problem?id=3009
题目大意:丢石头遇到障碍物停在障碍物的前一个格子中且障碍物消失,丢的条件是周围有一格为空,问从起点到终点最少丢多少次
题目分析:DFS条件注意下就行,这题是要先输入列再输入行
在这里附上两组数据:
6 2
2 0 1 1 1 1
1 1 1 1 1 3 输出: -1
6 2
2 0 1 1 0 1
1 1 1 1 3 1 输出: 4
#include <cstdio>#include <cstring>int dirx[4] = {0,-1,0,1}; int diry[4] = {-1,0,1,0};int map[22][22];int m, n;int ans;void DFS(int x, int y, int step) //深度优先搜索算法{ if(step > 10) //步数大于10返回 return; for(int i = 0; i < 4; i++) //枚举各个方向 { int xx = x + dirx[i]; int yy = y + diry[i]; //判断是否出界,当前步数是否小于之前的步数,当前位置是否非法(必须有空格才能扔) if(step < ans && xx > 0 && xx <= m && yy > 0 && yy <= n && map[xx][yy] != 1) { //当没有出界且格子为空时,一直沿着当前方向走 while(xx > 0 && xx <= m && yy > 0 && yy <= n && map[xx][yy] == 0) { xx += dirx[i]; yy += diry[i]; } //记录界外或者障碍物的前一步 int xx2 = xx - dirx[i]; int yy2 = yy - diry[i]; //如果出界则回到for换方向 //如果在界内且落在在终点将步数加1(因为从0开始的),这里不return,因为求最小要全部遍历完 //如果在界内且落在障碍物上,对障碍物前一步继续进行深搜,此时将障碍物设为0(障碍物被清除) //DFS完还要将其设回为1,因为要遍历所有的情况. if(xx > 0 && xx <= m && yy > 0 && yy <= n) { if(map[xx][yy] == 3) ans = step + 1; if(map[xx][yy] == 1) { map[xx][yy] = 0; DFS(xx2, yy2, step + 1); map[xx][yy] = 1; } } } }}int main(){ int sx, sy; //记录起点和终点的坐标 while(scanf("%d %d", &n, &m) != EOF && (m + n)) { ans = 11; for(int i = 1; i <= m; i++) { for(int j = 1; j <= n; j++) { scanf("%d",&map[i][j]); if(map[i][j] == 2) { map[i][j] = 0; //找到起点记录下后将其值设为0 sx = i; sy = j; } } } DFS(sx,sy,0); //起点步数为0 if(ans < 11) printf("%d\n",ans); else printf("-1\n"); }}
G题 棋盘问题
Time Limit: 1000MSMemory Limit: 10000KTotal Submissions: 23958
Accepted: 11859
Description
Input
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
Sample Input
2 1#..#4 4...#..#..#..#...-1 -1
Sample Output
21
题目链接:http://poj.org/problem?id=1321
题目大意:中文题,不解释了
题目分析:要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,采取行递增的方式搜索,只需要考察列的存储状态就行了,注意搜索一次后要复原即可。
#include <cstdio>#include <cstring>int n, k, ans;char map[10][10];bool vis[10]; //标记列是否已有棋子void dfs(int row, int num) //当前行,已经安放的棋子个数{ if(num == k) { ans++; return; } for(int i = row; i < n; i++) { for(int j = 0; j < n; j++) { if(map[i][j] == '#' && !vis[j]) { vis[j] = true; dfs(i + 1, num + 1); vis[j] = false; } } }}int main(){ while(scanf("%d %d",&n, &k) != EOF && (n + k) != -2) { ans = 0; memset(vis, false, sizeof(vis)); for(int i = 0; i < n; i++) scanf("%s", map[i]); dfs(0, 0); printf("%d\n", ans); }}
H题 Catch That Cow
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 49787 Accepted: 15623
Description
Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a pointN (0 ≤N ≤ 100,000) on a number line and the cow is at a pointK (0 ≤K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
* Walking: FJ can move from any point X to the pointsX- 1 orX+ 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
Input
Output
Sample Input
5 17
Sample Output
4
Hint
Source
题目链接:http://poj.org/problem?id=3278
题目大意:一条线上,给一个起点和一个终点,有三种走法,走一次1秒,位置坐标加1,减1和乘2,求从起点到终点的最短时间
题目分析:裸BFS,有可能n >= k,这时候只需要求n-k即可,n < k时,搜一搜就行了,千万注意!!虽然肯定有解,但是在BFS函数最后还是要return一个值,不然会wa
#include <cstdio>#include <queue>#include <cstring>using namespace std;int n, k;bool vis[200005];struct Node{ int num; int step;};int BFS(){ memset(vis, false, sizeof(vis)); queue <Node> q; Node st, cur, t; st.num = n; st.step = 0; vis[n] = true; q.push(st); while(!q.empty()) { t = q.front(); cur = t; q.pop(); if(t.num == k) return t.step; if(t.num + 1 < 200001 && !vis[t.num + 1]) { vis[t.num + 1] = true; t.num ++; t.step ++; q.push(t); } t = cur; if(t.num - 1 >= 0 && !vis[t.num - 1]) { vis[t.num - 1] = true; t.num --; t.step ++; q.push(t); } t = cur; if(t.num * 2 < 200001 && !vis[t.num * 2]) { vis[t.num * 2] = true; t.num *= 2; t.step ++; q.push(t); } } return 0;}int main(){ while(scanf("%d %d", &n, &k) != EOF) { if(n >= k) printf("%d\n", n - k); else printf("%d\n", BFS()); }}
- 基础搜索算法题解(D-H)
- 基础搜索算法题解(I-M)
- 基础搜索算法题解(N-R)
- 基础搜索算法题解(A-C)
- D-H算法
- C,D,F,G,H题 题解
- 【基础算法】搜索-二分搜索
- SEU寒假训练题解二 H Codeforces 435D
- JS基础算法题解析
- 【基础练习】【搜索】codevs1008 选数题解
- 搜索算法基础
- 百度、google海量数据搜索算法题解
- Uva11988 Broken Keyboard 题解(搜索算法)
- 【计蒜客】基础算法入门之深度搜索(2)蒜头学算术d
- 2D算法的基础
- 关于3D模型的搜索算法
- 搜索题解
- 搜索题解
- 在Azure Website 中配置 Entity Framework Connection String
- Wince NANDFlash启动和SD卡启动过程分析
- [FFMPEG-2]最想实现的第一点一个功能-从mp3中提取pcm数据,重采样和加wav头
- java入门—找素数的优化
- 【Qt5开发及实例】14、实现一个简单的文本编辑器3
- 基础搜索算法题解(D-H)
- java代码实现证书生成客户端证书 实现ssl双向认证
- 中国大学MOOC-翁恺-C语言程序习题第五周
- PHP设计模式——观察者模式
- Android service 生命周期
- Java 除与求余运算
- tr隐藏到显示宽度不对齐,变形
- 推荐一个Ubuntu下好用的蓝牙工具
- Fragment和Activity通信不过如此