1. 第一题-简单的搜索
题目描述:
算法实现:
#include <cstdio>
#include <algorithm>
#define INF 1000
#define MAXN 5
//保存迷宫
int maze[MAXN][MAXN];
//记忆化数组, 保存当前结点到终点的最短路劲
int record[MAXN][MAXN];
//记录还未访问的结点, 避免结点被重复访问
bool visit[MAXN][MAXN];
//方向数组
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
//读取数组
void init()
{
for(int i = 0; i < MAXN; i++)
{
for(int j = 0; j < MAXN; j++)
{
scanf("%d", &maze[i][j]);
}
}
}
//深度优先搜索结合记忆化数组
//当前结点的最短路径长度 = 它的所有临近结点最短路径长度的最小值 +1
int search(int y, int x)
{
if(y == 4 && x == 4)
{
return record[y][x] = 1;
}
if(record[y][x] < INF && record[y][x])
//如果记录的值不是无穷(即在以前的访问中记录为访问不到的状态)且已被
//记录过则直接返回记录的值
{
return record[y][x];
}
int min = INF;
for(int i = 0; i < 4; i++)
{
int newy = y+dir[i][0];
int newx = x+dir[i][1];
if(newy >= 0 && newy < MAXN
&& newx >= 0 && newx < MAXN
&& !maze[newy][newx]
&& !visit[newy][newx])
//若新节点未越界且可访问并未被访问就继续搜索
{
visit[newy][newx] = true;
min = std::min(min, search(newy, newx)+1);
visit[newy][newx] = false;
}
}
return record[y][x] = min;
}
//输出访问路径
void show(int y, int x, int len)
{
printf("(%d, %d)\n", y, x);
if(--len == 0)
{
return ;
}
for(int i = 0; i < 4; i++)
{
int newy = y+dir[i][0];
int newx = x+dir[i][1];
if(newy >= 0 && newy < MAXN
&& newx >= 0 && newx < MAXN
&& record[newy][newx] == len)
{
show(newy, newx, len);
}
}
}
void check()
{
printf("\n************\n");
printf("\n测试中间结果:\n");
printf("\n输出读取数组:\n");
for(int i = 0; i < MAXN; i++)
{
for(int j = 0; j < MAXN; j++)
{
printf("%d ", maze[i][j]);
}
putchar('\n');
}
printf("\n输出记忆化数组:\n");
for(int i = 0; i < MAXN; i++)
{
for(int j = 0; j < MAXN; j++)
{
printf("%-4d ", record[i][j]);
}
putchar('\n');
}
}
int main()
{
//从文件读取输入数据 ,方便测试, 正式提交时关闭
freopen("test2.in", "r", stdin);
init();
show(0, 0, search(0, 0));
check();
return 0;
}
输出结果:
2. 第二题-复杂的搜索
题目描述:
算法实现:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#define MAX 1000
using namespace std;
//位置
struct Pair
{
int y;
int x;
Pair(const int& y, const int& x)
{
this->y = y;
this->x = x;
}
};
//测试案例数
int n;
//行上限与列上限
int r , c;
//存储初始情况
char maze[MAX][MAX];
//搜索的四个方向
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
//存储火焰范围的边缘结点
queue<Pair> edgeFires;
//存储当前最临近的安全结点
queue<Pair> safeNodes;
//初始化数组和队列
void init()
{
memset(*maze, 0, r*(c+1));
int jy, jx;//存储初始位置
int fy, fx;
for(int i = 0; i < r; i++)
for(int j = 0; j <= c; j++)
{
maze[i][j] = getchar();
if(maze[i][j] == 'J')
{
jy = i;
jx = j;
}
if(maze[i][j] == 'F')
{
fy = i;
fx = j;
}
}
//放入第一个结点
edgeFires.push(Pair(fy, fx));
safeNodes.push(Pair(jy, jx));
}
//搜索安全路径
void search()
{
int newy, newx;
int count = 1;
//每次循环路径长度加一
while(true)
{
//如果火焰覆盖了整个场地或者没有安全结点可以走的时候说明无解
if(edgeFires.empty() || safeNodes.empty())
{
printf("IMPOSSIBLE\n");
break;
}
//绘出火焰的扩散范围
for(int i = edgeFires.size(); i > 0; i--)
{
Pair pair = edgeFires.front();
edgeFires.pop();
for(int i = 0; i < 4; i++)
{
newy = pair.y + dir[i][0];
newx = pair.x + dir[i][1];
if(newy < 0 || newy >= r
|| newx < 0 || newx >= c)
{
break;
}
//将火焰的边缘结点存入队列中
if(!(maze[newy][newx] == '#'
|| maze[newy][newx] == 'F'))
{
maze[newy][newx] = 'F';
edgeFires.push(Pair(newy, newx));
}
}
}
//判定当前位置是否是出口
for(int i = safeNodes.size(); i > 0; i--)
{
Pair pair = safeNodes.front();
//printf("%d %d\n", pair.y, pair.x);
if(pair.y == 0 || pair.y == r-1
|| pair.x == 0 || pair.x == c-1)
{
printf("%d\n", count);
return ;
}
safeNodes.pop();
for(int i = 0; i < 4; i++)
{
newy = pair.y + dir[i][0];
newx = pair.x + dir[i][1];
//越界检测
if(newy < 0 || newy >= r
|| newx < 0 || newx >= c)
{
break;
}
//在当前火焰覆盖的范围下向队列中加入下一个可走的临近结点
if(!(maze[newy][newx] == '#'
|| maze[newy][newx] == 'F'
|| maze[newy][newx] == 'J'))
{
maze[newy][newx] = 'J';
safeNodes.push(Pair(newy, newx));
}
}
}
count++;
}
}
//测试函数
void show()
{
for(int i = 0; i < r; i++)
{
for(int j = 0; j <= c; j++)
{
putchar(maze[i][j]);
}
}
putchar('\n');
}
int main()
{
//从文件读取输入数据 ,方便测试, 正式提交时关闭
freopen("test.in", "r", stdin);
scanf("%d", &n);
while(n--)
{
scanf("%d%d",&r,&c);
init();
//show();
search();
//show();
}
return 0;
}
输出结果: