1、POJ搜索题目题解poj搜索题总结初期篇 简单搜索(1)深度优先搜索 (poj2488,poj3009,poj1321)(2)广度优先搜索 (poj3278,poj1426,poj3126,poj3087.poj3414,poj2251,poj3083)(3)简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129) 看到这些题是不是很眼熟。没错,这就是某位大牛推荐初期要做的题。而这文章就是为这些题加上解题报告以及一些总结。 深度优先搜索poj2488:A Knights Journey 如果没有按字典序输出这个要求的话,就是简单的DFS,但是加上的话,就是麻烦题。这就要求
2、求出全部的走法或在行走时,按照某种顺序走。从时间上来说,当然是选择第二种了。若存在可行路线,则每个格子必然都走过。所以从A1开始,按照某种顺序走,若有解,则为所求,若无,则无解。/WA了N次,才发现是倒在字典序的手下/虽然题目没说,但是这道题最后一组数据后是没有空行的.否则会PE./若存在可行路线,则每个格子都走过。所以从(0,0)开始即可,不需要遍历每一个起始点/注意行走的方法(即MOV数组元素的排列),可以在找到可行解时,就使得其字典序最小 #include#include#include using namespace std; bool flag;string answer30;int
3、 chess3030; /这个的设置一定要与下面的转换相对应,之前就是不对应,错了N次int mov82=-1,-2,1,-2,-2,-1,2,-1,-2,1,2,1,-1,2,1,2; string GetPosition(int x,int y) /将X,Y坐标转换成题目要求的形式 string stmp; stmp+=(char)(y+A); /由于先出现的是Y坐标(如B3),所以MOV数组中的Y应从-2到2的顺序变化 stmp+=(char)(x+1); return stmp; void SaveIt(int p,int q) /保存下答案 for(int i=0;ip;+i) fo
4、r(int j=0;jq;+j) answerchessij=GetPosition(i,j); void dfs(int p,int q,int num,int x,int y) if( num=p*q ) flag=true; SaveIt(p,q); return; int xx,yy; for(int i=0;i=0 & xx=0 & yycases; while( cases- ) cinpq; flag=false; memset(chess,0,sizeof(chess); chess00=1; dfs(p,q,1,0,0); /output coutScenario #coun
5、t+:endl; if( flag ) for(i=1;i=p*q;+i) coutansweri; coutendl; else coutimpossibleendl; if( cases!=0 ) coutendl; return 0; poj1321:棋盘问题这题是简单的DFS,但题目有个地方说得不是很清楚,就是以“#”为标志的位置才能放棋子。/一次AC,用了DFS,以递归回溯的形式实现题目说得有点不清楚,以“#”为标志的位置才能入棋子 #include#include using namespace std; int count;int chess88; /能放棋子为1,不能为0,放下
6、棋子的是2 bool IsLegal(int x,int y) /由于一行只放一个,所以不用判断是否同行,这里只判断是否同列 for(int i=0;ix;+i) if( chessiy=2 ) return false; return true; void dfs(int n,int k,int num,int start) /num表示当前放了几颗棋子,START表示放棋子的超始行数 if( num=k ) +count; return ; for(int i=start;in;+i) for(int j=0;jnk & n!=-1 ) memset(chess,0,sizeof(ches
7、s); for(int i=0;in;+i) /get input for(int j=0;jctmp; if( ctmp=# ) chessij=1; count=0; dfs(n,k,0,0); coutcountendl; return 0; 广度优先搜索DFS一般是用来求全部解。但可以使其按照某种方式前进而达到求最优解的目的。而BFS则常用于求最优解,但其缺陷是空间要求过大。用BFS还有一个易错点,就是队列空间申请得过小(特别是用循环数组),导致有一些情况判断来不及判断就被覆盖掉。POJ 1321: Catch That Cow这题如果是用循环数组做的话,一定要注意我说的那个易错点。
8、/做BFS的第一题(用了类,STL中的队列),写完后,提交,TLE = =不用STL中的队列再加上剪枝后,就不TLE了,但一直RE = =(数组越界)不RE,然后又WA,发现这情况:0 100000 不能判断因为队列数组开得太小了,把还没来得及处理的数据给覆盖掉了改大后,才AC掉,阴险题#include/#include using namespace std; const int QMAX=50000; class NODE public: NODE(int xx=0,int ss=0):x(xx),step(ss) int x; int step; bool walk200001; /数组
9、一定要足够大,否则RENODE qQMAX; /队列int move32= 1,1,1,-1,2,0 ; /移动的方法 int main() / ifstream cin(test.in); int s,t,now,total,itmp; while( cinst ) now=0; total=1; memset(walk,0,sizeof(walk); /BFS qnow=NODE(s,0); walks=true; while( now!=total ) if( qnow%QMAX.x=t ) coutqnow%QMAX.stependl; break; for(int i=0;i3;+i
10、) itmp=(qnow%QMAX.x*movei0)+movei1; if( itmp=0 & !walkitmp ) /先判断ITMP范围,否则RE walkitmp=true; q(total+)%QMAX=NODE(itmp,qnow%QMAX.step+1); +now; return 0; POJ 1426:Find The Multiple#include#include/#include using namespace std; const int QMAX=10000; /定义队列最大长度 bool IsMultiple(string str,int n) /判断STR能否被
11、N整除 int len,mul,itmp; mul=10; itmp=0; len=str.size(); for(int i=0;ilen;+i) itmp=itmp*mul+(stri-0); if( itmpn & n!=0 ) now=0; total=1; /bfs qnow=1; while( now!=total ) if( IsMultiple(qnow%QMAX,n) ) coutqnow%QMAXendl; break; for(int i=0;i2;+i) q(total+)%QMAX=qnow%QMAX+letteri; +now; return 0; POJ 3126
12、 Prime Path也可以说是简单的BFS题。但有一点是注意的是SQRT函数可是被重载过。使用时,一定要指明其类型。BFS题,先求出全部四位的素数,然后再逐个尝试提交后CE,原来是SQRT函数作怪然后是WA,原因是素数判断错误,应该是J=SQRT(I),而不是JSQRT(I)修改后AC #include#include/#include using namespace std; class NODE public: NODE(int nn=0,int ss=0):num(nn),step(ss) int num; int step; const int PMAX=2000;const int
13、 QMAX=9000;int primePMAX;bool selectPMAX;NODE qQMAX; void init(int& len) /算出全部的素数 bool flag; for(int i=1000;i9999;+i) flag=true; for(int j=2;j1 ) return false; num1/=10; num2/=10; return true; int main() / ifstream cin(test.in); bool flag; int cases,n,m,len(0),now,total; init(len); cincases; while(
14、cases- ) cinnm; memset(select,0,sizeof(select); /bfs now=0; total=1; flag=false; qnow=NODE(n,0); while( now!=total ) if( qnow%QMAX.num=m ) coutqnow%QMAX.stependl; flag=true; break; for(int i=0;ilen;+i) if( !selecti & IsLegal(qnow%QMAX.num,primei) ) q(total+)%QMAX=NODE(primei,qnow%QMAX.step+1); selec
15、ti=true; +now; if( !flag ) coutImpossibleendl; return 0; POJ 3414:Pots相比起之前的BFS题,不同点就只有输出路径。这时只要在类中多加一个变量来记录上一步是哪个步骤。但要注意,不要用循环数组,因为会把前面的一些值给覆盖掉。/bfs,简单题,注意怎样回溯出使用了哪些步骤就可以了/第一次WA,不能过的数据:91 100 95 答案是170/错误原因:walk数组开小了,导致有一些情况不能判断/从100X100改为201X201后就AC了#include#include#include#include using namespace
16、 std; const int QMAX=9000; class NODE public: NODE(int x1=0,int x2=0,int x3=0,int x4=0):a(x1),b(x2),method(x3),pre(x4) int a; int b; int method; /记录是用什么方法得到这步 int pre; /记录前一个步骤是哪个(数组的下标),回溯时用到; NODE qQMAX; /队列数组开大点,不要用循环数组bool walk201201; /注意最大应该是200,就是这里开小了,导致WAstring str7= ,FILL(1),FILL(2),DROP(1)
17、,DROP(2),POUR(1,2),POUR(2,1) ; int main() ifstream cin(test.in); bool flag; int a,b,c,now,total,count; while( cinabc ) memset(walk,0,sizeof(walk); now=0; total=1; flag=false; walk00=true; qnow=NODE(0,0,0,0); while( now!=total ) if( qnow.a=c | qnow.b=c ) flag=true; break; /fill if( qnow.a!=a & !walka
18、qnow.b) /method=1 means FILL(1) qtotal+=NODE(a,qnow.b,1,now); walkaqnow.b=true; if( qnow.b!=b & !walkqnow.ab ) /method=2 means FILL(2) qtotal+=NODE(qnow.a,b,2,now); walkqnow.ab=true; /drop if( qnow.a!=0 & !walk0qnow.b) /method=3 means DROP(1) qtotal+=NODE(0,qnow.b,3,now); walk0qnow.b=true; if( qnow.
19、b!=0 & !walkqnow.a0 ) /method=4 means DROP(2) qtotal+=NODE(qnow.a,0,4,now); walkqnow.a0=true; /pour if( qnow.a!=0 & qnow.b!=b ) /method=5 means POUR(1,2) if( qnow.a+qnow.b=b & !walkqnow.a-(b-qnow.b)b ) qtotal+=NODE(qnow.a-(b-qnow.b),b,5,now); walkqnow.a-(b-qnow.b)b=true; else if( qnow.a+qnow.b=a & !
20、walkaqnow.b-(a-qnow.a) ) qtotal+=NODE(a,qnow.b-(a-qnow.a),6,now); walkaqnow.b-(a-qnow.a)=true; else if( qnow.a+qnow.ba & !walkqnow.a+qnow.b0 ) qtotal+=NODE(qnow.a+qnow.b,0,6,now); walkqnow.a+qnow.b0=true; +now; if( flag ) count=0; stack sta; while( now!=0 ) /使用堆栈来存放步骤 +count; sta.push(strqnow.method
21、); now=qnow.pre; coutcountendl; while( !sta.empty() ) coutsta.top()endl; sta.pop(); else coutimpossibleendl; return 0;1606 POJ 3087:Shufflem Up在SHUFFLE时只有一种情况是合法,就是S2只能在下面。其它就是简单的BFS了。/第一道一次AC的BFS,注意在SHUFFLE时,只能S2在下面,即不会出现S1在下面的情况#include#include#include using namespace std; class NODE public: NODE(
22、string ss=,int is=0):str(ss),step(is) string str; int step; const int QMAX=9000;NODE qQMAX; string Shuffle(string s1,string s2) string tmp; for(int i=0;is1.size();+i) tmp+=s2i; tmp+=s1i; return tmp; void GetS1AndS2(string str,string& s1,string& s2) /get s1 and s2 from s12 int len=s1.size(); for(int i=0;ilen;+i) s1i=stri; for(int j=0;jlen;+j) s2j=strj+len; bool IsWalk(string str,int qlen) /is str appeared? for(int i=0;iqlen;+i) if( qi.str=str ) return true; return false; int main() ifstream
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1