练习:经典搜索题
来源:互联网 发布:轻松的工作 知乎 编辑:程序博客网 时间:2024/06/05 19:22
暴力搜索不管是在平面矩阵还是在树中都是骗分的好方法。
接下来带来两道经典搜索题的题解。
推箱子
POJ 1475 推箱子
推箱子大家都玩过吧。要求推箱子的步数最少,满足条件的情况下人走的步数最少,又满足以上条件的情况下spj。推箱子的动作用大写表示,无解则输出Impossible.
先枚举箱子的上下左右,如果有空位,搜索人能不能走到。
#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<algorithm>#include<string>#include<math.h>using namespace std;int bx,by,sx,sy,tx,ty,m,n,d[]={-1,1,0,0,0,0,-1,1},vis[25][25];//是否走到过char caozuo[]={'n','s','w','e'},c[25][25];bool biaoji[25][25][4];//标记盒子的位置以及每个方向struct box{int x,y,sx,sy;string answer;}nowbox,prebox;//sx,sy标记盒子在x,y时人的位置struct ren{int x,y;string answer;}nowman,preman;inline char daxie(char c){return (c-32);}//大写bool bfs2(int s,int e,int a,int b,int p,int q)//判断人能不能走到盒子旁{queue<ren> r;if (s<0||s>m||e<0||e>n||c[s][e]=='#') return false;//不存在的nowman.x=p,nowman.y=q,nowman.answer="";memset(vis,0,sizeof vis);vis[a][b]=1,vis[p][q]=1;for (r.push(nowman);!r.empty();)//平凡的bfs { nowman=r.front(),r.pop(); if (nowman.x==s&&nowman.y==e) return true; for (int i=0;i<4;i++) { preman.x=nowman.x+d[i]; preman.y=nowman.y+d[i+4]; if (preman.x>0&&preman.x<=m&&preman.y>0&&preman.y<=n&&!vis[preman.x][preman.y]&&c[preman.x][preman.y]!='#') { preman.answer=nowman.answer+caozuo[i];//加上走的一步 vis[preman.x][preman.y]=1; r.push(preman); } } }return false;}bool bfs1()//一样的{queue<box> b;nowbox.x=bx,nowbox.y=by,nowbox.answer="";nowbox.sx=sx,nowbox.sy=sy;for (b.push(nowbox);!b.empty();) { nowbox=b.front(),b.pop(); if (nowbox.x==tx&&nowbox.y==ty) return true; for (int i=0;i<4;i++) { prebox.x=nowbox.x+d[i]; prebox.y=nowbox.y+d[i+4]; if (prebox.x>0&&prebox.x<=m&&prebox.y>0&&prebox.y<=n&&!biaoji[prebox.x][prebox.y][i]&&c[prebox.x][prebox.y]!='#') if (bfs2(prebox.x-2*d[i],prebox.y-2*d[i+4],nowbox.x,nowbox.y,nowbox.sx,nowbox.sy)) { prebox.sx=nowbox.x; prebox.sy=nowbox.y; prebox.answer=nowbox.answer+nowman.answer+daxie(caozuo[i]); biaoji[prebox.x][prebox.y][i]=1; b.push(prebox); } } }return false;}int main(){for (int t,cases=0;scanf("%d %d",&m,&n),m,n;puts(""))//做着做着不要忘记还有一个换行 { memset(biaoji,false,sizeof biaoji); for (int i=1;i<=m;i++) for (int j=1;j<=n;j++) { scanf(" %c",&c[i][j]); if (c[i][j]=='S') sx=i,sy=j; if (c[i][j]=='T') tx=i,ty=j; if (c[i][j]=='B') bx=i,by=j; } printf("Maze #%d\n",++cases); if (bfs1()) cout<<nowbox.answer.c_str()<<endl; else puts("Impossible."); }}
八数码
POJ 1077 Eight
八数码也是经典问题。这题是spj,只要输出的路径是正确的都给对。
这里用了A*算法。
#include<cstdio>#include<queue>#include<cstring>#include<algorithm>#include<ctype.h>#include<string>using namespace std;const int boss=4e5;struct node{int c[3][3],hash,f,g,h,x,y;//hash即为状态bool operator <(const node n1) const{return h!=n1.h?h>n1.h:g>n1.g;}bool check(){return x<0||y<0||x>=3||y>=3?0:1;}};int jiecheng[]={1,1,2,6,24,120,720,5040,40320},d[]={1,-1,0,0,0,0,-1,1},vis[boss+10],pre[boss+10],zhongdian=322560;//终点的hash是322560int getstate(node n)//求一个图的状态{int opt[12],k=0;for (int i=0;i<3;i++) for (int j=0;j<3;++j) opt[k++]=n.c[i][j];int sum=0;for (int i=0;i<9;i++) { int cnt=0; for (int j=0;j<i;j++) if (opt[i]<opt[j]) cnt++; sum+=cnt*jiecheng[i]; }return sum;}int gujia(node n)//估计还有多少步到达{int sum=0;for (int i=0;i<3;i++) for (int j=0;j<3;++j) if (n.c[i][j]) { int x=(n.c[i][j]-1)/3,y=(n.c[i][j]-1)%3; sum+=abs(x-i)+abs(y-j); }return sum;}bool judge(node n)//判断逆序对是否是偶数,不是直接剪枝{int opt[12],k=0;for (int i=0;i<3;i++) for (int j=0;j<3;++j) opt[k++]=n.c[i][j];int sum=0;for (int i=0;i<9;i++) for (int j=i+1;j<9;++j) if (opt[i]&&opt[j]&&opt[i]>opt[j]) sum++;return !(sum&1);}void a_star(node st)//A*算法,具体可以看看别人的博客{priority_queue<node> q;for (q.push(st);!q.empty();) { node n=q.top();q.pop(); for (int i=0;i<4;i++) { node xia=n; xia.x+=d[i],xia.y+=d[i+4]; if (!xia.check()) continue; swap(xia.c[xia.x][xia.y],xia.c[n.x][n.y]); xia.hash=getstate(xia); if (vis[xia.hash]==-1) { xia.h=gujia(xia); xia.g++; xia.f=xia.g+xia.h; pre[xia.hash]=n.hash; q.push(xia); vis[xia.hash]=i; } if (xia.hash==zhongdian) return; } }}void print()//输出路径{int nextit=zhongdian;char pr[]={'d','u','l','r'};string answer;answer.clear();for (;pre[nextit]!=-1;nextit=pre[nextit]) answer+=pr[vis[nextit]];int len=answer.size();for (int i=len-1;i>=0;i--) putchar(answer[i]);puts("");}int main(){for (char str[100];gets(str)!=NULL;print()) { node t; memset(vis,-1,sizeof vis); memset(pre,-1,sizeof pre); for (int k=0,i=0;str[k]!='\0';k++) if (isdigit(str[k])) t.c[i/3][i++%3]=str[k]-'0'; else if (str[k]=='x') t.x=i/3,t.y=i%3,t.c[t.x][t.y]=0,i++; t.hash=getstate(t); vis[t.hash]=-2; t.g=0,t.h=gujia(t); t.f=t.g+t.h; if (!judge(t)) {puts("unsolvable");continue;} if (t.hash==zhongdian) {puts("");continue;} a_star(t); }}
谢谢大家的观看。
阅读全文
0 0
- 练习:经典搜索题
- 搜索题练习
- 经典搜索题
- Sticks 经典搜索题
- 经典搜索题
- plsql经典测试题--练习
- 经典练习
- 【练习】经典算法练习
- 本校自制搜索题练习第二弹
- 搜索练习7 /poj.org/problem3279/ Fliptile/黑白棋翻转经典题型 DFS
- pku上一些经典的搜索题
- pku上一些经典的搜索题
- poj3278-简单搜索练习
- 练习二 搜索 1015
- 练习深度优先搜索
- 蓝桥杯搜索练习1
- 蓝桥杯搜索练习2
- 百度搜索练习
- 《ReactNative》之百度地图打包时遇到的问题
- SGU 499 Max Gcd——枚举因子
- 将本地项目上传至Github
- QTableView表格视图的列宽设置
- Wayland(1):X Window的前生今世
- 练习:经典搜索题
- 连续总结第二十七天
- CString 和int相互转化
- 查找死锁的方法
- 面向对象(一)
- quartz 实现定时作业 初级
- 在cocos2dx界面中嵌入android的webview。(c++篇,包含c++和java的交互)
- ANSI和UNICODE字符串处理函数
- CentOS 7服务器安全配置(未完待续)