第四个专题了,初期基本搜索:
都是水题,两天完全可以刷完。。。
(1)、深度优先搜索
1、poj2488
题意:给出一个国际棋盘的大小,判断马能否不重复的走过所有格,并记录下其中按字典序排列的第一种路径。
分析:爆搜。。。
#include <iostream>
#include <cstring>
using namespace std;
const int N = 35;
int vis[N][N];
int p, q, flag;
char b[500];
int dir[8][2] = {-1, -2, 1, -2, -2, -1, 2, -1, -2, 1, 2, 1, -1, 2, 1, 2};
void dfs(int x, int y, int cnt) {
if (cnt == p*q) {
cout << "A1";
for (int i = 2; i < 2*cnt; i++) cout << b[i];
cout << endl << endl;
flag = 1;
return;
}
for (int i = 0; i < 8 && !flag; i++) {
int tx = x + dir[i][0], ty = y + dir[i][1];
if (tx < 1 || tx > p || ty < 1 || ty > q) continue;
if (!vis[tx][ty]) {
vis[tx][ty] = 1;
b[2*cnt] = 'A' + ty - 1;
b[2*cnt+1] = '1' + tx - 1;
dfs(tx, ty, cnt+1);
vis[tx][ty] = 0;
}
}
}
int main() {
int t, ca = 0;
cin >> t;
while (t--) {
cin >> p >> q;
cout << "Scenario #" << ++ca << ':' << endl;
memset(vis, 0, sizeof(vis));
flag = 0;
vis[1][1] = 1;
dfs(1, 1, 1);
if (!flag) cout << "impossible" << endl << endl;
}
return 0;
}
2、poj3083
题意:给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走先输出左转优先时,从S到E的步数,再输出右转优先时,从S到E的步数,最后输出S到E的最短步数
分析:dfs找左转和右转步数,bfs找最短路。
#include <cstdio>
#include <cstring>
int w, h, c, a;
int Sx, Sy, Ex, Ey;
int cnt, flag, tag;
int dir[4][2] = {0, -1, -1, 0, 0, 1, 1, 0};
char maze[50][50];
int vis[50][50];
int que[2500][2];
void DFS(int x, int y, int cnt) {
if (maze[x][y] == 'E') {
printf("%d ", cnt);
tag = 0;
return ;
}
if (tag) for (int i = a+c, j = 0; j < 4; j++, i -= c) {
if (i < 0) i = 3;
if (i > 3) i = 0;
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if (tx > h || tx < 1 || ty > w || ty < 1) continue;
if (tag && !vis[tx][ty] && maze[tx][ty] != '#') {
a = i;
DFS(tx, ty, cnt+1);
}
}
}
void BFS() {
int fir = 0, sec = 0;
que[sec][0] = Sx;
que[sec++][1] = Sy;
int step = 1;
while(fir < sec && !vis[Ex][Ey]) {
int tmp = sec;
step++;
while(fir < tmp && !vis[Ex][Ey]) {
int x = que[fir][0];
int y = que[fir++][1];
for(int i = 0; i < 4; i++) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if (tx > h || tx < 1 || ty > w || ty < 1) continue;
if(!vis[tx][ty] && maze[tx][ty] != '#') {
que[sec][0] = tx;
que[sec++][1] = ty;
vis[tx][ty] = 1;
}
}
}
}
printf("%d\n", step);
}
int main() {
int t, i, j;
scanf("%d", &t);
while (t--) {
memset(maze, 0, sizeof(maze));
memset(vis, 0, sizeof(vis));
scanf("%d %d", &w, &h);
getchar();
for (i = 1; i <= h; i++) {
for (j = 1; j <= w; j++) {
scanf("%c", &maze[i][j]);
if (maze[i][j] == 'S') Sx = i, Sy = j;
else if (maze[i][j] == 'E') Ex = i, Ey = j;
}
getchar();
}
for (i = 0; i < 4; i++)
if (maze[Sx+dir[i][0]][Sy+dir[i][1]] == '.') break;
vis[Sx][Sy] = 1;
a = i; tag = 1; c = -1;
DFS(Sx, Sy, 1);
a = i; c = 1; tag = 1;
DFS(Sx, Sy, 1);
BFS();
}
return 0;
}
3、poj3009
题意:要求把一个冰壶从起点“2”用最少的步数移动到终点“3”,其中0为移动区域,1为石头区域,冰壶一旦想着某个方向运动就不会停止,也不会改变方向(想想冰壶在冰上滑动),除非冰壶撞到石头1或者到达终点3,冰壶撞到石头后,冰壶会停在石头前面,此时(静止状态)才允许改变冰壶的运动方向,而该块石头会破裂,石头所在的区域由1变为0. 也就是说,冰壶撞到石头后,并不会取代石头的位置。终点是一个摩擦力很大的区域,冰壶若到达终点3,就会停止在终点的位置不再移动。
分析:直接搜索,题目细节是沿着某一行出发会遇到石头才会停止,不停止则失败,停止时石头也会消失,步数不能超过10步。
#include <cstdio>
using namespace std;
int square[30][30];
int w, h, sx, sy;
int minnum;
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
void DFS(int x, int y, int cnt) {
if (cnt >= 10) return ;
for (int i = 0; i < 4; i++) {
int flag = 1, tag = 0;
int nx = x + dir[i][0], ny = y + dir[i][1];
while (1) {
if (nx < 1 || nx > h || ny < 1 || ny > w) {
flag = 0;
break;
}
if (square[nx][ny] == 1) {
tag = 1;
break;
}
if (square[nx][ny] == 3 && minnum > ++cnt) {
minnum = cnt;
return ;
}
nx += dir[i][0];
ny += dir[i][1];
}
if (!flag) continue;
if (tag) {
square[nx][ny] = 0;
nx -= dir[i][0];
ny -= dir[i][1];
if (nx == x && ny == y) {
square[nx+dir[i][0]][ny+dir[i][1]] = 1;
continue;
}
DFS(nx, ny, cnt+1);
square[nx+dir[i][0]][ny+dir[i][1]] = 1;
}
}
}
int main() {
while (scanf("%d %d", &w, &h), w+h) {
minnum = 9999;
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++){
scanf("%d", &square[i][j]);
if (square[i][j] == 2){