简单搜索
棋盘问题
POJ-1321
思路:这个键盘问题可归为八皇后问题的翻版,而这道题是一个行的全排列枚举,意思是每一行都有机会且几率平等被选到,最终选出满足条件的K行,那么方案数加一。所以所以可以用回溯法来实现这个行全排列问题。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX_N = 10;
int n,k;
bool col[MAX_N]; ///用来判断某列是否已经有元素了
char maze[MAX_N][MAX_N];
int ans = 0;
void dfs(int base,int cnt)
{
///2
for(int i=0;i<n;i++){
if(maze[base][i]=='#'&&col[i]==0){
if(cnt==k-1){
ans++;
//return; 不能return 后面的值还没有dfs
}
else{
col[i] = 1;
///3
for(int l = base+1; n-l+1>=k-cnt; l++)
dfs(l,cnt+1);
col[i] = 0;
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&k)==2&&n+1){
memset(col,0,sizeof(col));
memset(maze,0,sizeof(maze));
ans = 0;
char str[10];
for(int i=0;i<n;i++){
scanf("%s",str);
for(int j=0;j<n;j++){
maze[i][j] = str[j];
}
}
///1
for(int i=0;i<n-k+1;i++){
dfs(i,0); ///代表dfs初始行与已填数目
}
printf("%d\n",ans);
}
return 0;
}
用回溯法实现行的全排列选k个,那就要注意代码的三个循环(代码里有注释分别对应1,2,3):对于循环1,枚举前面n-k+1列的行,而后面的行没有机会填满k个元素。然后循环2,类似八皇后的做法,对每一列进行枚举,情况满足的时候就递归。这里注意,满足递归条件不代表dfs可以return出,后面的元素同样有可能满足条件,所以要跑完整个循环。循环三当前一列满足条件,应当枚举的是下面的行,而下面的行每一个机会都相等,所以base下的每一行都要枚举出来,这样就实现了行的全排列枚举。
思想:对于回溯法应该有新的认识。回溯法服务于最开始的根节点,用于寻找满足条件或路径最长的dfs路,不管怎么搜索,根节点都是最初dfs的根节点,一直为其服务。而这道题可以看出,这道题的行(根节点)不应该只是第一行,而应该是1,2,…n-k+1行。同时还需注意要实现全排列,dfs里面的枚举应该也需循环,对于base下方的每一行都要枚举出来。
Dungeon Master
POJ-2251
这道题将搜索扩展成三维迷宫。实际考的:bfs路径记录。
思路:将vis开成三维空间,然后上bfs求最短路。bfs分为五个方向,东南西北以及下方。注意往下走一层也是step+1,所以这五个方向完全平等。循环五次即可。注意判断。
代码:
#include<stdio.h>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
char map[30][30][30]; //记录节点信息
int sta[30][30][30]; //标记是否访问
int base[6][3] = { {-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1} };
int L, R, C;
struct Piont
{
int x, y, z; //位置坐标
int step; //出发点到该点的步数
};
struct Piont s; //起点
struct Piont e; //终点
struct Piont curp; //跳出循环时的节点
/******************判断是否到达终点*********************/
bool success(struct Piont cur)
{
if (cur.x == e.x && cur.y == e.y && cur.z == e.z)
return true;
else
return false;
}
/**************判断该点是否合法*************************/
bool check(int x, int y, int z)
{
if ((x >= 0) && (x < L) && (y >= 0) && (y < R) && (z >= 0) && (z < C) && (!sta[x][y][z]) && (map[x][y][z] == '.' || map[x][y][z] == 'E'))
return true;
else
return false;
}
///广搜
void bfs()
{
struct Piont next;
queue<Piont>q;
q.push(s);
//int flag = 0;
while (!q.empty())
{
curp = q.front();
q.pop();
if (success(curp))
return;
else
{
sta[curp.x][curp.y][curp.z] = 1;
for (int i = 0; i < 6; i++)
{
next.x = curp.x + base[i][0];
next.y = curp.y + base[i][1];
next.z = curp.z + base[i][2];
if (check(next.x, next.y, next.z)) //扩展队列
{
next.step = curp.step + 1;
sta[next.x][next.y][next.z] = 1;
q.push(next);
}
}
}
}
}
int main()
{
while (scanf("%d%d%d", &L, &R, &C))
{
if((L == 0) && (R == 0) && (C == 0))
break;
memset(sta, 0, sizeof(sta));
for (int i = 0; i < L; i++) {
getchar();
for (int j = 0; j < R; j++) {
for (int k = 0; k < C; k++)
{
scanf("%c", &map[i][j][k]);
if (map[i][j][k] == 'S') {
s.x = i;
s.y = j;
s.z = k;
s.step = 0;
}
else if (map[i][j][k] == 'E')
{
e.x = i;
e.y = j;
e.z = k;
}
}
getchar();
}
}
bfs();
if (curp.x == e.x && curp.y == e.y && curp.z == e.z)
printf("Escaped in %d minute(s).\n", curp.step);
else
printf("Trapped!\n");
}
return 0;
}
这里再贴上bfs记录路径的伪代码:
bfs
q.push(); ///将一个节点push进来,last=1;
int last=1,cur=0 ///cur为下一路径的点的总数
while(!q.empty()){
q.pop();
last--;
...bfs一系列操作,满足条件的点放入队列时cnt++
if(last==0){
last = cur; ///将这个路径的点继承给last,cur清零继续记录下一路径的点的个数
step++;
cur = 0;
}
}
return;
Catch That Cow
POJ-3278
一道bfs记录路径长度的题目。一维的。难度没有上一题难。注意边界处理
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=100001;
bool vis[maxn];//标记数组
int step[maxn];//记录到了每一位置所走的步数
queue <int> q;//定义队列
int bfs(int n,int k)
{
int head,next;
q.push(n); //开始FJ在n位置,n入队
step[n]=0;
vis[n]=true; //标记已访问
while(!q.empty()) //当队列非空
{
head=q.front(); //取队首
q.pop(); //弹出对首
for(int i=0;i<3;i++) //FJ的三种走法
{
if(i==0) next=head-1;
else if(i==1) next=head+1;
else next=head*2;
if(next<0 || next>=maxn) continue; //排除出界情况
if(!vis[next]) //如果next位置未被访问
{
q.push(next); //入队
step[next]=step[head]+1; //步数+1
vis[next]=true; //标记已访问
}
if(next==k) return step[next]; //当遍历到结果,返回步数
}
}
}
int main()
{
int n,k;
while(cin>>n>>k)
{
memset(step,0,sizeof(step));
memset(vis,false,sizeof(vis));
while(!q.empty()) q.pop(); //注意调用前要先清空
if(n>=k) printf("%d\n",n-k);
else printf("%d\n",bfs(n,k));
}
return 0;
}
Fliptile
POJ-3279
其实是一道状态压缩题,不知道为什么归到了搜索上。是状压dp的一个衍生,要同时记录进行操作的opt数组。一个图可能没有答案,也可能有多个答案,字典序最小的输出。
思路:初始行数据是小于等于15的,容易想到二进制状态压缩dp,而这道题恰巧是这么做。对第一行二进制枚举操作点,每个操作点tap一次(自己及周围五个格翻转)那么对于第二行要操作的点就显而易见了,即都是在第一行还剩余1(黑格)的下方tap一次,因为这样就能保证第一行全为0(白格)。那么这样一直操作2~n行(我将N看成n行,输入不要错就行)最后检查最后一行是否全为0即可。
代码:
#include<cstring>
#include<memory>
#include<cstdio>
using namespace std;
const int MAX_N = 17;
const int inf = 0x3f3f3f3f;
int n,m;
int minn = inf;
int tap_cnt = 0;
int chess[MAX_N][MAX_N],cur[MAX_N][MAX_N];
int oper[MAX_N][MAX_N],ans[MAX_N][MAX_N];
void tap(int x,int y)
{
cur[x][y]^=1,cur[x-1][y]^=1,cur[x+1][y]^=1,cur[x][y+1]^=1,cur[x][y-1]^=1;
}
bool ok()
{
for(int i=1;i<=m;i++){
if(oper[1][i]){
tap(1,i);
tap_cnt++;
}
}
for(int i=2;i<=n;i++){
for(int j=1;j<=m;j++){
if(cur[i-1][j]){
tap(i,j);
tap_cnt++;
oper[i][j] = 1;
}
}
}
for(int i=1;i<=m;i++){
if(cur[n][i]) return 0;
}
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&chess[i][j]);
}
}
for(int i=0;i<(1<<m);i++){
tap_cnt = 0;
memset(oper,0,sizeof(oper)),memcpy(cur,chess,sizeof(cur));
for(int j=m;j>=1;j--){
oper[1][j] = (i>>(m-j))&1;
}
if(ok()&&tap_cnt>0&&tap_cnt<minn){
minn = tap_cnt;
memcpy(ans,oper,sizeof(ans));
}
}
if(minn!=inf){
for(int i=1;i<=n;i++){
int flag = 1;
for(int j=1;j<=m;j++){
if(!flag) printf(" ");
flag = 0;
printf("%d",ans[i][j]);
}
printf("\n");
}
}
else{
printf("IMPOSSIBLE\n");
}
return 0;
}
Find The Multiple
POJ-1426
这个博客写的很好,下面代码仿照他的来写的。https://blog.csdn.net/qq_42964711/article/details/81938661
是一道双入口bfs+同余模的问题,好题。题目的注释在代码中写的比较清楚。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int mod[1000000] = {0};
int ans[1000000] = {0};
int n;
int main()
{
while(scanf("%d",&n)==1&&n){
memset(mod,0,sizeof(mod));
mod[1] = 1%n; ///1(2)
int i;
for(i=2;mod[i-1]!=0;i++){
mod[i] = (mod[i/2]*10 + i%2)%n;
///mod[i/2]相当于对于二进制来说推了一位,
///举一反三,如果这道题只有0,1,2可以选,那么就是mod[i/3],
///相当于3进制中退了一位
///再用同余模定理处理一下
}
i--; ///退一位,原本i-1已经符合条件了
int pm = 0;
while(i){
ans[pm++] = i%2;
i/=2;
}
while(pm){
printf("%d",ans[--pm]);
}
printf("\n");
}
return 0;
}
Prime Path
POJ-3126
简单的bfs最短路题,直接上代码。
代码:
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
using namespace std;
struct Q
{
int x[4];
int s;
}no,de;
queue<Q> iq;
int n,a,b,ans,t[4];
int vir[10008];
bool isPrime( int x )
{
for( int i=2; i<=sqrt(x); i++ )
if( x%i == 0 )
return false;
return true;
}
int wirte( int* a)
{
return a[0]*1000+a[1]*100+a[2]*10+a[3];
}
void bfs( )
{
while( !iq.empty() )
iq.pop();
ans=0;
memset(vir,0,sizeof(vir));
no.s=0;
for( int i=0; i<4; i++ )
{
no.x[3-i]=a%10;
a/=10;
}
iq.push(no);
vir[wirte(no.x)] = 1 ;
while( !iq.empty() )
{
no = iq.front();
iq.pop();
if( wirte(no.x)==b )
{
printf("%d\n",no.s);
return ;
}
for( int i=0; i<4; i++ )
{
de=no;
for( int j=0; j<=9; j++ )
{
if( i==0 && j==0 ) continue;
de.x[i] = j ;
if( !vir[wirte(de.x)] && isPrime(wirte(de.x)))
{
vir[wirte(de.x)] = 1 ;
de.s=no.s+1;
iq.push(de);
}
}
}
}
printf("Impossible\n");
}
int main()
{
scanf("%d",&n);
while( n-- )
{
scanf("%d%d",&a,&b);
bfs();
}
return 0;
}
Shuffle’m Up
也不是搜索…是一道模拟题,模拟卡牌的叠放顺序。如果经过有限次模拟得到了与之前某个步骤相同的排法,说明无解,反之得到答案的话,就将答案输出。
#include<cstdio>
#include<cstring>
#include<set>
#include<string>
#include<iostream>
using namespace std;
set<string> S;
int main()
{
int N;
scanf("%d",&N);
int kase = 0;
char s1[405],s2[405],s12[805],fin[805];
while(N--){
int length;
scanf("%d",&length);
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
memset(s12,0,sizeof(s12));
memset(fin,0,sizeof(fin));
S.clear();
scanf("%s%s%s",s1,s2,fin);
for(int i=0;i<length*2;i++){
if(i&1){
s12[i] = s1[i/2];
}
else{
s12[i] = s2[i/2];
}
}
S.insert(s12);
bool flag = 0;
int step = 1;
char buf[805] = {0};
while(1){
//cout<<s12<<endl;
if(strcmp(s12,fin)==0){
flag = 1;
break;
}
step++;
//cout<<"l:"<<length<<endl;
for(int i=0;i<length*2;i++){
if((i&1)==0){
buf[i] = s12[i/2+length];
}
else{
buf[i] = s12[i/2];
}
}
//cout<<"B:"<<buf<<'\n';
if(S.count(buf)){
break;
}
strcpy(s12,buf);
S.insert(s12);
}
if(flag)
printf("%d %d\n",++kase,step);
else{
printf("%d %d\n",++kase,-1);
}
}
return 0;
}
Pots
POJ-3414
这是一道好题,是一个记录ans“路径名称”的一道题。下面的代码采用了链式前向星的思想将路径储存到op数组中,相信学过的同学应该都能看懂。但这道题不知道为何tle了,修改了几处也还是tle。如果哪位大牛看到这道题解,帮忙解释一下。
代码:
#include<cstdio>
#include<set>
#include<cstdlib>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
using namespace std;
const int MAX_N = 20000; ///n(A) * n(B) 最多为10000种情况
const int MAX_V = 105;
int LA,LB,LC;
struct node
{
int A;
int B;
int ind;
node(int A=0,int B=0,int ind=0)
:A(A),B(B),ind(ind)
{}
};
struct OP
{
int pre;
string s1;///记录指向此点过程的字符串
OP(int pre=0,string s1="\0")
:pre(pre),s1(s1)
{}
}op[MAX_N];
typedef pair<int,int> PII;
//set<PII> S; 用set导致TLE
int vis[MAX_V][MAX_V] = {0};
queue<node> q;
int step = 0;
int index = 0;
bool bfs(int a,int b)
{
int id = 0;
vis[a][b] = 1;
op[id] = OP(-1,"0");///根本不会访问到
q.push(node(a,b,id++));
int cur = 0,last = 1;
while(!q.empty()){
node SE = q.front();
q.pop();
last--;
int SA = SE.A,SB = SE.B,ID = SE.ind;
//printf("test:%d %d\n",SA,SB);
if(SA==LC||SB==LC){
index = ID;
return true;
}
for(int i=0;i<6;i++){
int buf_L1 = SA,buf_L2 = SB;
if(i==0){
///0~2为对A操作
buf_L1 = LA;
if(!vis[buf_L1][buf_L2]){
vis[buf_L1][buf_L2] = 1;
op[id] = OP(ID,"FILL(1)");
q.push(node(buf_L1,buf_L2,id++));
cur++;
}
}
else if(i==1){
buf_L1 = 0;
if(!vis[buf_L1][buf_L2]){
vis[buf_L1][buf_L2] = 1;
op[id] = OP(ID,"DROP(1)");
q.push(node(buf_L1,buf_L2,id++));
cur++;
}
}
else if(i==2){
//printf("arr1:%d %d\n",buf_L1,buf_L2);
if(buf_L2+buf_L1<=LB){
buf_L2 += buf_L1;///反过来,太tmd隐蔽了
buf_L1 = 0;///
}
else{
buf_L1 -= LB - buf_L2;
buf_L2 = LB;
}
//printf("arr2:%d %d\n",buf_L1,buf_L2);
if(!vis[buf_L1][buf_L2]){
vis[buf_L1][buf_L2] = 1;
op[id] = OP(ID,"POUR(1,2)");
q.push(node(buf_L1,buf_L2,id++));
cur++;
}
}
///3~5为对B操作
else if(i==3){
buf_L2 = LB;
if(!vis[buf_L1][buf_L2]){
vis[buf_L1][buf_L2] = 1;
op[id] = OP(ID,"FILL(2)");
q.push(node(buf_L1,buf_L2,id++));
cur++;
}
}
else if(i==4){
buf_L2 = 0;
if(!vis[buf_L1][buf_L2]){
vis[buf_L1][buf_L2] = 1;
op[id] = OP(ID,"DROP(2)");
q.push(node(buf_L1,buf_L2,id++));
cur++;
}
}
else{
if(buf_L1+buf_L2<=LA){
buf_L1 += buf_L2;
buf_L2 = 0;
}
else{
buf_L2 -= LA - buf_L1;
buf_L1 = LA;
}
if(!vis[buf_L1][buf_L2]){
vis[buf_L1][buf_L2] = 1;
op[id] = OP(ID,"POUR(2,1)");
//printf("arr\n");
q.push(node(buf_L1,buf_L2,id++));
cur++;
}
}
}
if(last==0){
step++;
last = cur;
cur = 0;
}
}
return false;
}
void ans_print()
{
vector<string> vec;
printf("%d\n",step);
int p = index;
while(p!=0){
vec.push_back(op[p].s1);
p = op[p].pre;
}
for(int i=vec.size()-1;i>=0;i--){
printf("%s\n",vec[i].c_str());
}
}
int main()
{
scanf("%d%d%d",&LA,&LB,&LC);
if(bfs(0,0)){
ans_print();
}
else{
printf("impossible\n");
}
return 0;
}
Fire Game
FZU-2150
这道题,好题!
首先是bfs(或不回溯dfs)找连通块个数,这题要写一份。
其次是找一图的一个点,这个点能以最短的时间扩散完整个图,那么这个最短的时间是多少?可以结合图论知识,其实就是找树的最大直径除以二,得到的就是最短时间。把这个连通块想成一颗树,随便选取连通块的一点bfs,找到距离这点最远的点P,再从P点bfs一次,到最远的点的距离就是树的直径,(1
+m(p点距离))/2就是答案。
但一图找两个点扩散,就只能枚举连通块的点啦。
以下就是一点扩散没优化过的代码。
代码:
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
char map[150][150];
int vis[150][150];
int cnt,n,m,ans;
const int inf=0x3f3f3f3f;
struct node{
int x;
int y;
int step;
};
bool check(int x,int y){
if(x<0||x>=n||y<0||y>=m||vis[x][y]==1||map[x][y]!='#') return false;
return true;
}
bool checkAll(){
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(map[i][j]=='#'&&vis[i][j]==0) return false;
}
return true;
}
int bfs(node a,node b){
queue<node> que;
memset(vis,0,sizeof(vis));
que.push(a);
que.push(b);
int steps=0;
while(!que.empty()){
node p=que.front();
que.pop();
if(vis[p.x][p.y]) continue;
vis[p.x][p.y]=1;
steps=p.step;
if(check(p.x+1,p.y)){
node next=p;
next.step++;
next.x++;
que.push(next);
}
if(check(p.x,p.y+1)){
node next=p;
next.step++;
next.y++;
que.push(next);
}
if(check(p.x-1,p.y)){
node next=p;
next.step++;
next.x--;
que.push(next);
}
if(check(p.x,p.y-1)){
node next=p;
next.step++;
next.y--;
que.push(next);
}
}
return steps;
}
int main(){
int ans=inf;
int t,kase=1;
cin>>t;
vector<node> collect;
while(t--){
ans=inf;
scanf("%d%d",&n,&m);
memset(vis,0,sizeof(vis));
collect.clear();
for(int i=0;i<n;i++)
scanf("%s",&map[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(map[i][j]=='#'){
node c;
c.x=i;
c.y=j;
c.step=0;
collect.push_back(c);
}
}
for(int i=0;i<collect.size();i++)
for(int j=i;j<collect.size();j++){
collect[i].step=collect[j].step=0;
int aos=bfs(collect[i],collect[j]);
if(checkAll()) ans=min(ans,aos);
}
if(ans==inf) printf("Case %d: %d\n",kase++,-1);
else printf("Case %d: %d\n",kase++,ans);
}
}
Fire!
UVA-11624
相同速度的同步双bfs。人向四处搜索的速度与火向四周蔓延的速度一样,所以要记录每个火焰和人扩散的每个点的步数。好题,同步双bfs(一个bfs写下)的写法如下。
注意,两个bfs的地位是平等的,所以应该一个bfs上完后,就上另外一个bfs。
另外开始可能有多个火焰口,要注意
代码:
#include<bits/stdc++.h>
using namespace std;
int R,C;
const int MAX_N = 1005;
const int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
char maze[MAX_N][MAX_N] = {0};
int vis[MAX_N][MAX_N] = {0};
struct node
{
int x,y;
node(int x=0,int y=0):x(x),y(y){}
};
node J,F[MAX_N*MAX_N];
int cnt_F = 0;
bool out(int x,int y)
{
return x<1||x>R||y<1||y>C;
}
bool in(int x,int y)
{
return 1<=x&&x<=R&&1<=y&&y<=C;
}
queue<node> J_q;
queue<node> F_q;
int kkkkase = 0;
int bfs(int tx,int ty)
{
while(!J_q.empty()) J_q.pop();
while(!F_q.empty()) F_q.pop();
J_q.push(node(tx,ty));
for(int i=0;i<cnt_F;i++)
F_q.push(node(F[i].x,F[i].y));
vis[tx][ty] = 1;
int last = 1,cur = 0,step = 1;
int last_f = cnt_F,cur_f = 0;
bool flag = 1;
while(1){
#ifdef test
cout<<++kkkkase<<":\n";
for(int i=1;i<=R;i++){
for(int j=1;j<=C;j++){
cout<<vis[i][j]<<' ';
}
cout<<'\n';
}
#endif
if(!flag) break;///说明人已经无路可走了
while(!F_q.empty()){
node FE = F_q.front();
F_q.pop();
last_f--;
for(int i=0;i<4;i++){
int ex = FE.x + dir[i][0],ey = FE.y + dir[i][1];
if(in(ex,ey)&&!vis[ex][ey]){
vis[ex][ey] = 2;
F_q.push(node(ex,ey));
cur_f++;
}
}
if(last_f==0){
last_f = cur_f;
cur_f = 0;
break;///跳出这层火的循环,开始人的扩散
}
}
while(1){
if(J_q.empty()){
flag = 0;
break;
}
node PE = J_q.front();
J_q.pop();
last--;
for(int i=0;i<4;i++){
int ex = PE.x + dir[i][0],ey = PE.y + dir[i][1];
if(out(ex,ey)){
return step;
}
if(in(ex,ey)&&!vis[ex][ey]){
vis[ex][ey] = step;
J_q.push(node(ex,ey));
cur++;
}
}
if(last==0){
last = cur;
cur = 0;
step++;
break;///跳出人的bfs,进行下一轮step+1的循环
}
}
}
return -1;
}
int main()
{
//ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T;
cin>>T;
while(T--){
cin>>R>>C;
memset(maze,0,sizeof(maze));
memset(vis,0,sizeof(vis));
//memset(F,0,sizeof(F));
cnt_F = 0;
///getchar()可能(在这道题就是)会导致RE
///队列出入一定要判断是否为空,不然会RE
///while(!q.empty()) pop是初始化的方法
for(int i=1;i<=R;i++){
char str[MAX_N] = {0};
cin>>str;
for(int j=1;j<=C;j++){
maze[i][j] = str[j-1];
if(maze[i][j]=='#') vis[i][j] = 1;
else if(maze[i][j]=='J') J = node(i,j),vis[i][j] = 0;
else if(maze[i][j]=='F') F[cnt_F++] = node(i,j),vis[i][j] = 2;
else vis[i][j] = 0;
}
}
int ans;
if((ans=bfs(J.x,J.y))!=-1){
cout<<ans<<'\n';
}
else{
cout<<"IMPOSSIBLE"<<'\n';
}
}
return 0;
}
迷宫问题
POJ-3984
如果上一道题明白透了,那这道题就不成问题。
bfs+路径储存,用链式前向星的思想完成就可以了。
代码:(可能代码不是链式前向星完成的,因为这道题很久之前就做过了,直接粘上代码)
#include<stdio.h>
#include<string.h>
#define max 10
int map[max][max];
int vis[max][max];
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
struct node
{
int x,y;
}queue[max*max];
int a[max*max];
int b[max*max];
int cnt;
int p[max*max];
void print(int k)
{
int i;
int t=p[k];
if(t==0)
{
printf("(0, 0)\n");
printf("(%d, %d)\n",a[k],b[k]);
}
else
{
print(t);
printf("(%d, %d)\n",a[k],b[k]);
}
}
void bfs(int x,int y)
{
struct node now,pre;
queue[0].x=0;
queue[0].y=0;
int e=0,h=1;
p[0]=-1;
while(e<h)
{
pre=queue[e];
if(pre.x==4&&pre.y==4)
{
print(e);
return;
}
int i;
for(i=0;i<4;i++)
{
now.x=pre.x+dir[i][0];
now.y=pre.y+dir[i][1];
if(now.x>=0&&now.x<5&&now.y>=0&&now.y<5&&!vis[now.x][now.y]&&map[now.x][now.y]==0)
{
vis[now.x][now.y]=1;
queue[h]=now;
a[h]=now.x;
b[h]=now.y;
p[h]=e;
h++;
}
}
e++;
}
return;
}
int main()
{
int i,j;
cnt=0;
for(i=0;i<5;i++)
{
for(j=0;j<5;j++)
{
scanf("%d",&map[i][j]);
}
}
memset(vis,0,sizeof(vis));
bfs(0,0);
return 0;
}
这里是分割线
题目尚且没有补完,仅先开此博客。