ImageVerifierCode 换一换
格式:DOCX , 页数:31 ,大小:24.42KB ,
资源ID:30668617      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/30668617.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(ACM必做50题的解题搜索.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

ACM必做50题的解题搜索.docx

1、ACM必做50题的解题搜索POJ1011 Sticks 搜索+强剪枝(终于AC了,分享经验) 这个题目是不是贪心的,我就是第一次用了贪心,一直WA,相当的悲剧,贪心错误的sample:7 15 11 8 8 8 4 3 2 1,所以大家还是全部搜索。但是全部搜索必须剪枝,不然肯定是TLE的,而且本体属于强剪枝,少剪了也是TLE。经典搜索题,果然是到处充斥着剪枝才能过啊,我的代码离剪到极限还差很多题目给出一大堆小棍子的长度,需要把他们拼成几根长度相等的大棍子,求大棍子的最短长度看自己剪枝方法的效果时候,可以添设一个变量来记录递归次数如剪枝4:没有这个剪枝的情况下对以下数据需要40万次递归,而加上

2、这个剪枝后减少到了4万多次对数据:4515 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8 #include #include using namespace std;int sticks65;int used65;int n,len;bool dfs(int i,int l,int t)/i为当前试取的棍子序号,l为要拼成一根完整的棍子还需要的长度,t初值为所有棍子总长度 if(l=0) t-=len; if(t=0)return true; fo

3、r(i=0;usedi;+i); /剪枝1:搜索下一根大棍子的时候,找到第一个还没有使用的小棍子开始 usedi=1; /由于排序过,找到的第一根肯定最长,也肯定要使用,所以从下一根开始搜索 if(dfs(i+1,len-sticksi,t)return true; usedi=0; t+=len; else for(int j=i;j0&(sticksj=sticksj-1&!usedj-1) /剪枝2:前后两根长度相等时,如果前面那根没被使用,也就是由前面那根 continue; /开始搜索不到正确结果,那么再从这根开始也肯定搜索不出正确结果,此剪枝威力较大 if(!usedj&l=sti

4、cksj) /剪枝3:最简单的剪枝,要拼成一根大棍子还需要的长度L=当前小棍子长度,才能选用 l-=sticksj; usedj=1; if(dfs(j,l,t)return true; l+=sticksj; usedj=0; if(sticksj=l) /剪枝4:威力巨大的剪枝,程序要运行到此处说明往下的搜索失败,若本次的小棍长度刚好填满剩下长度,但是后 break; /面的搜索失败,则应该返回上一层 return false;bool cmp(const int a, const int b) return ab; int main() while(cinn&n) int sum=0;

5、for(int i=0;isticksi; sum+=sticksi; usedi=0; sort(sticks,sticks+n,cmp); /剪枝5:从大到小排序后可大大减少递归次数 bool flag=false; for(len=sticks0;len=sum/2;+len) /剪枝6:大棍长度一定是所有小棍长度之和的因数,且最小因数应该不小于小棍中最长的长度 if(sum%len=0) if(dfs(0,len,sum) flag=true; coutlenendl; break; if(!flag) coutsumendl; return 0;本文来自CSDN博客,转载请标明出处:

6、 poj 1033 Defragment题意:磁盘整理,按照从第一个文件到最后一个文件的顺序排放,而且每个文件的碎片按原来的顺序放在一起,要求转移的次数最少。解:其实根本不用搜索,一开始想搜索想了很久,上网找解题报告也没找到(这么水的一题竟然没有解题报告),于是开始自已想。其实碎片的排列只有二种情况:1. A0碎片没有放在原来的位置,而它原来的位置正好是空的。而A1碎片也刚好没有放在原来的位置,而b原来的位置之前一直被A0占领,同样还有A2碎片没有在原来位置,而其原来的位置之前一直被A1占领,以此递推直到Ai,没有碎片要放在Ai的位置为止。这种情况称为链。2. 基本上同1一样,不过,一开始的时

7、候A0的原来位置并不是空的,而是最后的那个Ai占领着,这种情况称为环。解决方法:1。对于1,只需要从A0开始一个一个按顺序放到原来的位置上即可。2。对于2,只需要从环中的任何一个节点开始,先将这个节点放到从尾部开始数起的空位,然后以链的方式处理,最后再将这个节点的数放回到最后一个节点的位置。主要数据结构:qi:放在第i个位上的数应该放在第qi个位上。di:应该放在第i个位上的数,现在放在了第di个位上。#include using namespace std;int n,k,tmp,t,index,pi;int q10000;int d10000;bool optneed;int main()

8、 optneed=false; memset(q,-1,10000*sizeof(int); memset(d,-1,10000*sizeof(int); scanf(%d%d,&n,&k); int counter=0; for(int j=0;jk;j+) scanf(%d,&t); for(int i=0;it;i+) scanf(%d,&tmp); tmp-; qtmp=counter; dcounter=tmp; counter+; /put nodes whose correct place is empty and solve the chains. for(int i=0;in

9、;i+) if(qi=i|qi=-1) continue; optneed=true; if(qqi=-1) printf(%d %dn,i+1,qi+1); qqi=qi;qi=-1; index=i; while(dindex!=-1) printf(%d %dn,dindex+1,index+1); qdindex=-1;qindex=index; index=dindex; continue; if(optneed=true) /solve the rings for(int i=0;i=0;tmp-) if(qtmp=-1) break; printf(%d %dn,i+1,tmp+

10、1); qtmp=qi;qindex=-1; while(index!=qtmp) printf(%d %dn,dindex+1,index+1); qindex=index;qdindex=-1; index=dindex; printf(%d %dn,tmp+1,index+1); qindex=qtmp;qtmp=-1; else printf(No optimization neededn); return 0;本文来自CSDN博客,转载请标明出处:poj 1129 Channel Allocation(图着色) 题意: 用中继器(repeater)给每个接受者(receiver)发送

11、信号,为了防止信号干扰,两个相邻的广播站之间的中继器要不相同。问至少需要多少个中继器。 这个问题相当于给定个图,如果要求把所有顶点涂上颜色,使得相邻顶点具有不同的颜色,问最少需要几种不同的颜色。经典的图着色问题。思路: 根据给出的点构造邻接矩阵,顶点相邻的位置置1,不同的置0。因为图着色问题颜色最多是四种颜色。所以1种,2种,3种,4种,一个一个试,如果返回回来的着色方案总数不是0说明可行,为用的最少的颜色数。 #include #include #include #define N 27int gNN, num, n; int xN;int ok(int t) int i; for(i =

12、1; i n) num+; else for(i=1; i=m; i+) xt = i; if(ok(t) traceback(t+1, m); xt = 0; int main() int i, j; char ch; while(scanf(%d, &n) & n) memset(g, 0, sizeof(g); ch = getchar(); for(i=1; i=n; i+) ch = getchar(); ch = getchar(); while(isalpha(ch = getchar() /输入这里要注意 gich-A+1 = 1; gch-A+1i = 1; for(j=1;

13、 j=4; j+) num = 0; traceback(1, j); if(num != 0) if(num = 1) printf(1 channel needed.n); /还有这里 else printf(%d channels needed.n, j); break; return 0;POJ 2049 Finding Nemo题目不复杂,其实就是走迷宫,但是通过题的描述去确定一些参数来描述当前的迷宫是得想想。而且有些细节你也得考虑,你要考虑整个迷宫的形状,要考虑初始的时候可行的迷宫入口,迷宫的入口有时是有门,有些是没门的下面是我的代码,写得个人觉得是相当冗繁,ANYWAY,总算解决

14、了。题目的思路是利用广搜,从可行的迷宫入口开始去搜索下一层的新的可行节点。记录已经搜索到的节点的所通过的门数,一搜到Nemo的位置时立马返回该节点的所通过的门数,这时所通过的门数是最少的(这里大家可以思考一下为什么)。#include #include #define MAX_N 210 /最大限度边界using namespace std;int vMAX_N + 1MAX_N + 1; /vij表示到格子ij的最小步骤数int roundMAX_N + 1MAX_N + 14; /记录当前格子四面边界的类型, 0:air 1:wall 2:doorint wn, dn, startXI,

15、startYI, minSteps; /wn:墙的数目,dn:门的数目,起始点对应的格子坐标double startXF, startYF; /起始点的输入浮点坐标 int dirarray42 = 0, 1, 0, -1, -1, 0, 1, 0; /方向数组,走四个方向对坐标的变化/上:0, 下:1, 左:2, 右:3/入bfs队列的元素类型struct elem /x, y记录这个格子的坐标; dir记录是从当前格子的哪个方向进入这个格子的,上:0, 下:1, 左:2, 右:3 int x, y, dir, stepnum; /stepnum记录到达当前格子所需的步骤数;queue bf

16、sq; /bfs的队列/取当前方向的对面方向void changeDir(int orgignal, int &newDir) if(orgignal = 0) newDir = 1; else if(orgignal = 1) newDir = 1; else if(orgignal = 2) newDir = 3; else newDir = 2;/当断当前坐标是否在合法范围内bool inRange(int x, int y) return x = 0 & x = 0 & y = 205;void bfs() /将Demo的位置入队列作为bfs的起始位置 while(!bfsq.empt

17、y() bfsq.pop(); elem curelem, newelem; curelem.x = startXI; curelem.y = startYI; curelem.dir = -1; curelem.stepnum = 0; vstartXIstartYI = 0; bfsq.push(curelem); int curx, cury, curdir, cursteps, newx, newy, newdir, newsteps, d; while(!bfsq.empty() curelem = bfsq.front(); bfsq.pop(); curx = curelem.x

18、; cury = curelem.y; curdir = curelem.dir; cursteps = curelem.stepnum; /到达出发点 if(curx = 0 & cury = 0) /更新所需位置的最优值 if(cursteps minSteps) minSteps = cursteps; continue; /遍历当前格子的四个方向,尝试往这四个方向走 for(d = 0; d 4; d+) /不能往回走 if(d != curdir) /所走方向不能是墙 if(roundcurxcuryd != 1) /得到新的格子坐标 newx = curx + dirarrayd0

19、; newy = cury + dirarrayd1; /新坐标在合法范围内 if(inRange(newx, newy) /计算所有方向相对目标格子所在的方位 changeDir(d, newdir); /门,步骤数+1 if(roundcurxcuryd = 2) newsteps = cursteps + 1; else /空气,步骤数不变 newsteps = cursteps; /判断这个新格子的新状态是否需要入队列 if(vnewxnewy = 0xbf | newsteps vnewxnewy) & newsteps minSteps) vnewxnewy = newsteps;

20、 newelem.x = newx; newelem.y = newy; newelem.stepnum = newsteps; newelem.dir = newdir; bfsq.push(newelem); int main() int i, j, x, y, d, t; while(scanf(%d%d, &wn, &dn) & !(wn = -1 & dn = -1) minSteps = INT_MAX; memset(v, 12, sizeof(v); memset(round, 0, sizeof(round); for(i = 1; i = wn; i+) scanf(%d%

21、d%d%d, &x, &y, &d, &t); /输入的预处理,将线段(墙)转换为相应格子对应的四面边界 if(d = 1) for(j = y + 1; j = y + t; j+) roundxj2 = roundx - 1j3 = 1; else for(j = x; j x + t; j+) roundjy0 = roundjy + 11 = 1; for(i = 1; i = dn; i+) scanf(%d%d%d, &x, &y, &d); /输入的预处理,将线段(门)转换为相应格子的四面边界方向 if(d = 1) roundxy + 12 = roundx - 1y + 13

22、 = 2; else roundxy0 = roundxy + 11 = 2; scanf(%lf%lf, &startXF, &startYF); /将Demo的位置转换为格子坐标 startXI = startXF; startYI = startYF + 1; /题目中的异常数据 if(startXI 199 | startYI 199) printf(0n); else bfs(); if(minSteps = INT_MAX) printf(-1n); else printf(%dn, minSteps); return 0;POJ 2056 The Separator in Gri

23、d这道题我曾经是想过深搜的,就一条线路一条线路的搜,不过后来,事实证明,所需的时间很多,老是TLE,弄得我都烦了,后来实在没办法之下,重新考虑题意。其实对于i层的点来说,它只需知道i-1层的哪些点可以作为起始点和到达这些点所需的最小的sep(short for separator),这样算法的效率就跟层数相关,也跟每一层寻找起始点的操作相关,应该是O(MN),而n200,所以算法的效率是有保障的。广搜#include #include struct Nodeint x;int y;int chessBox 200 200 ; /标记每一点是M,S还是Bint step 200 200 ; /标

24、记每一点到达时的最小步数Node status 200*200 ; /标记哪些节点是可继续展开(也就是可以形成separator的点)的节点int M,N;int last;void FindNext( Node curStatus ) /从curStatus去寻找下面的可用节点int curStep = step curStatus.x curStatus.y ;int m = curStatus.x+1;int n = curStatus.y;if ( m = N-1 ) /如果是已经来到了倒数第二层,由于最后一层肯定只有一个separator的节点。如果它有两个或以上,可能证明其中一个删

25、去后它仍是一个sep.这样对于每个可用节点,我们直接考虑它是否可以直接向下一步形成seq. if ( chessBox m n ) int tempStep = curStep+1; step m n = tempStep; elsewhile( chessBox m n = 2 ) /如果不是倒数第二层,就向左展开可用节点 可用的节点满足:它的正下方有节点存在,如果这个节点是可继续延展的节点。 if ( chessBox m+1 n = 2 ) int tempStep = curStep + curStatus.y - n +1;/更新到达该节点的最小需要的Sep数 if ( step m

26、 n = 0) step m n = tempStep; (status last ).x = m; (status last ).y = n; +last; else if( step m n tempStep ) step m n = tempStep; -n;n = curStatus.y+1;/向右展开节点并更新while ( chessBox m n = 2 ) if ( chessBox m+1 n = 2 ) int tempStep = curStep+ n - curStatus.y+1; if ( step m n = 0) step m n = tempStep; (st

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1