ACM必做50题的解题搜索文档格式.docx

上传人:b****3 文档编号:18441065 上传时间:2022-12-16 格式:DOCX 页数:26 大小:24.48KB
下载 相关 举报
ACM必做50题的解题搜索文档格式.docx_第1页
第1页 / 共26页
ACM必做50题的解题搜索文档格式.docx_第2页
第2页 / 共26页
ACM必做50题的解题搜索文档格式.docx_第3页
第3页 / 共26页
ACM必做50题的解题搜索文档格式.docx_第4页
第4页 / 共26页
ACM必做50题的解题搜索文档格式.docx_第5页
第5页 / 共26页
点击查看更多>>
下载资源
资源描述

ACM必做50题的解题搜索文档格式.docx

《ACM必做50题的解题搜索文档格式.docx》由会员分享,可在线阅读,更多相关《ACM必做50题的解题搜索文档格式.docx(26页珍藏版)》请在冰豆网上搜索。

ACM必做50题的解题搜索文档格式.docx

&

(sticks[j]==sticks[j-1]&

!

used[j-1]))//剪枝2:

前后两根长度相等时,如果前面那根没被使用,也就是由前面那根

continue;

//开始搜索不到正确结果,那么再从这根开始也肯定搜索不出正确结果,此剪枝威力较大

if(!

used[j]&

l>

=sticks[j])//剪枝3:

最简单的剪枝,要拼成一根大棍子还需要的长度L>

=当前小棍子长度,才能选用

l-=sticks[j];

used[j]=1;

if(dfs(j,l,t))returntrue;

l+=sticks[j];

used[j]=0;

if(sticks[j]==l)//剪枝4:

威力巨大的剪枝,程序要运行到此处说明往下的搜索失败,若本次的小棍长度刚好填满剩下长度,但是后

break;

//面的搜索失败,则应该返回上一层

returnfalse;

}

boolcmp(constinta,constintb)

{

returna>

b;

intmain()

while(cin>

>

n&

n)

intsum=0;

for(inti=0;

i<

++i)

cin>

sticks[i];

sum+=sticks[i];

sort(sticks,sticks+n,cmp);

//剪枝5:

从大到小排序后可大大减少递归次数

boolflag=false;

for(len=sticks[0];

len<

=sum/2;

++len)//剪枝6:

大棍长度一定是所有小棍长度之和的因数,且最小因数应该不小于小棍中最长的长度

if(sum%len==0)

if(dfs(0,len,sum))

flag=true;

cout<

<

endl;

flag)

sum<

return0;

本文来自CSDN博客,转载请标明出处:

poj1033Defragment

题意:

磁盘整理,按照从第一个文件到最后一个文件的顺序排放,而且每个文件的碎片按原来的顺序放在一起,要求转移的次数最少。

解:

其实根本不用搜索,一开始想搜索想了很久,上网找解题报告也没找到(这么水的一题竟然没有解题报告),于是开始自已想。

其实碎片的排列只有二种情况:

1.A0碎片没有放在原来的位置,而它原来的位置正好是空的。

而A1碎片也刚好没有放在原来的位置,而b原来的位置之前一直被A0占领,同样还有A2碎片没有在原来位置,而其原来的位置之前一直被A1占领,以此递推直到Ai,没有碎片要放在Ai的位置为止。

这种情况称为链。

2.基本上同1一样,不过,一开始的时候A0的原来位置并不是空的,而是最后的那个Ai占领着,这种情况称为环。

解决方法:

1。

对于1,只需要从A0开始一个一个按顺序放到原来的位置上即可。

2。

对于2,只需要从环中的任何一个节点开始,先将这个节点放到从尾部开始数起的空位,然后以链的方式处理,最后再将这个节点的数放回到最后一个节点的位置。

主要数据结构:

q[i]:

放在第i个位上的数应该放在第q[i]个位上。

d[i]:

应该放在第i个位上的数,现在放在了第d[i]个位上。

intn,k,tmp,t,index,pi;

intq[10000];

intd[10000];

booloptneed;

intmain(){

optneed=false;

memset(q,-1,10000*sizeof(int));

memset(d,-1,10000*sizeof(int));

scanf("

%d%d"

&

n,&

k);

intcounter=0;

for(intj=0;

k;

j++){

%d"

t);

t;

i++){

tmp);

tmp--;

q[tmp]=counter;

d[counter]=tmp;

counter++;

}

//putnodeswhosecorrectplaceisemptyandsolvethechains.

if(q[i]==i||q[i]==-1)continue;

optneed=true;

if(q[q[i]]==-1){

printf("

%d%d\n"

i+1,q[i]+1);

q[q[i]]=q[i];

q[i]=-1;

index=i;

while(d[index]!

=-1){

d[index]+1,index+1);

q[d[index]]=-1;

q[index]=index;

index=d[index];

if(optneed==true){

//solvetherings

for(tmp=n-1;

tmp>

=0;

tmp--)if(q[tmp]==-1)break;

i+1,tmp+1);

q[tmp]=q[i];

q[index]=-1;

while(index!

=q[tmp]){

q[index]=index;

q[d[index]]=-1;

tmp+1,index+1);

q[index]=q[tmp];

q[tmp]=-1;

}elseprintf("

Nooptimizationneeded\n"

);

poj1129ChannelAllocation(图着色)

用中继器(repeater)给每个接受者(receiver)发送信号,为了防止信号干扰,两个相邻的广播站之间的中继器要不相同。

问至少需要多少个中继器。

这个问题相当于给定—个图,如果要求把所有顶点涂上颜色,使得相邻顶点具有不同的颜色,问最少需要几种不同的颜色。

经典的图着色问题。

思路:

根据给出的点构造邻接矩阵,顶点相邻的位置置1,不同的置0。

因为图着色问题颜色最多是四种颜色。

所以1种,2种,3种,4种,一个一个试,如果返回回来的着色方案总数不是0说明可行,为用的最少的颜色数。

stdio.h>

string.h>

ctype.h>

#defineN27

intg[N][N],num,n;

intx[N];

intok(intt)

inti;

for(i=1;

i<

=n;

i++)

if(i!

=t)

if(g[t][i]==1&

x[i]==x[t])

return1;

voidtraceback(intt,intm)

if(t>

n)

num++;

for(i=1;

=m;

x[t]=i;

if(ok(t))

traceback(t+1,m);

x[t]=0;

inti,j;

charch;

while(scanf("

&

n)&

memset(g,0,sizeof(g));

ch=getchar();

{

while(isalpha(ch=getchar()))//输入这里要注意

g[i][ch-'

A'

+1]=1;

g[ch-'

+1][i]=1;

for(j=1;

j<

=4;

j++)

num=0;

traceback(1,j);

if(num!

=0)

if(num==1)

1channelneeded.\n"

//还有这里

else

%dchannelsneeded.\n"

j);

POJ2049FindingNemo

题目不复杂,其实就是走迷宫,但是通过题的描述去确定一些参数来描述当前的迷宫是得想想。

而且有些细节你也得考虑,你要考虑整个迷宫的形状,要考虑初始的时候可行的迷宫入口,迷宫的入口有时是有门,有些是没门的~~~~下面是我的代码,写得个人觉得是相当冗繁,ANYWAY,总算解决了。

题目的思路是利用广搜,从可行的迷宫入口开始去搜索下一层的新的可行节点。

记录已经搜索到的节点的所通过的门数,一搜到Nemo的位置时立马返回该节点的所通过的门数,这时所通过的门数是最少的(这里大家可以思考一下为什么)。

queue>

#defineMAX_N210//最大限度边界

intv[MAX_N+1][MAX_N+1];

//v[i][j]表示到格子[i][j]的最小步骤数

intround[MAX_N+1][MAX_N+1][4];

//记录当前格子四面边界的类型,0:

air1:

wall2:

door

intwn,dn,startXI,startYI,minSteps;

//wn:

墙的数目,dn:

门的数目,起始点对应的格子坐标

doublestartXF,startYF;

//起始点的输入浮点坐标

intdirarray[4][2]={{0,1},{0,-1},{-1,0},{1,0}};

//方向数组,走四个方向对坐标的变化

//上:

0,下:

1,左:

2,右:

3

//入bfs队列的元素类型

structelem

//x,y记录这个格子的坐标;

dir记录是从当前格子的哪个方向进入这个格子的,上:

intx,y,dir,stepnum;

//stepnum记录到达当前格子所需的步骤数

};

queue<

elem>

bfsq;

//bfs的队列

//取当前方向的对面方向

voidchangeDir(intorgignal,int&

newDir)

if(orgignal==0)newDir=1;

elseif(orgignal==1)newDir=1;

elseif(orgignal==2)newDir=3;

elsenewDir=2;

//当断当前坐标是否在合法范围内

boolinRange(intx,inty)

returnx>

=0&

x<

=205&

y>

y<

=205;

voidbfs()

//将Demo的位置入队列作为bfs的起始位置

while(!

bfsq.empty())bfsq.pop();

elemcurelem,newelem;

curelem.x=startXI;

curelem.y=startYI;

curelem.dir=-1;

curelem.stepnum=0;

v[startXI][startYI]=0;

bfsq.push(curelem);

intcurx,cury,curdir,cursteps,newx,newy,newdir,newsteps,d;

bfsq.empty())

curelem=bfsq.front();

bfsq.pop();

curx=curelem.x;

cury=curelem.y;

curdir=curelem.dir;

cursteps=curelem.stepnum;

//到达出发点

if(curx==0&

cury==0)

//更新所需位置的最优值

if(cursteps<

minSteps)

minSteps=cursteps;

//遍历当前格子的四个方向,尝试往这四个方向走

for(d=0;

d<

4;

d++)

//不能往回走

if(d!

=curdir)

//所走方向不能是墙

if(round[curx][cury][d]!

=1)

//得到新的格子坐标

newx=curx+dirarray[d][0];

newy=cury+dirarray[d][1];

//新坐标在合法范围内

if(inRange(newx,newy))

//计算所有方向相对目标格子所在的方位

changeDir(d,newdir);

//门,步骤数+1

if(round[curx][cury][d]==2)

newsteps=cursteps+1;

else//空气,步骤数不变

newsteps=cursteps;

//判断这个新格子的新状态是否需要入队列

if((v[newx][newy]==0xbf||newsteps<

v[newx][newy])&

newsteps<

v[newx][newy]=newsteps;

newelem.x=newx;

newelem.y=newy;

newelem.stepnum=newsteps;

newelem.dir=newdir;

bfsq.push(newelem);

inti,j,x,y,d,t;

wn,&

dn)&

!

(wn==-1&

dn==-1))

minSteps=INT_MAX;

memset(v,12,sizeof(v));

memset(round,0,sizeof(round));

i<

=wn;

%d%d%d%d"

x,&

y,&

d,&

//输入的预处理,将线段(墙)转换为相应格子对应的四面边界

if(d==1)

for(j=y+1;

j<

=y+t;

round[x][j][2]=round[x-1][j][3]=1;

for(j=x;

x+t;

round[j][y][0]=round[j][y+1][1]=1;

=dn;

%d%d%d"

d);

//输入的预处理,将线段(门)转换为相应格子的四面边界方向

round[x][y+1][2]=round[x-1][y+1][3]=2;

round[x][y][0]=round[x][y+1][1]=2;

%lf%lf"

startXF,&

startYF);

//将Demo的位置转换为格子坐标

startXI=startXF;

startYI=startYF+1;

//题目中的异常数据

if(startXI<

0||startXI>

199||startYI<

0||startYI>

199)

0\n"

bfs();

if(minSteps==INT_MAX)printf("

-1\n"

elseprintf("

%d\n"

minSteps);

POJ2056TheSeparatorinGrid

这道题我曾经是想过深搜的,就一条线路一条线路的搜,不过后来,事实证明,所需的时间很多,老是TLE,弄得我都烦了,后来实在没办法之下,重新考虑题意。

其实对于i层的点来说,它只需知道i-1层的哪些点可以作为起始点和到达这些点所需的最小的sep(shortforseparator),这样算法的效率就跟层数相关,也跟每一层寻找起始点的操作相关,应该是O(M×

N),而n<

200,所以算法的效率是有保障的。

广搜

memory.h>

structNode

intx;

inty;

intchessBox[200][200];

//标记每一点是'

M'

'

S'

还是'

B'

intstep[200][200];

//标记每一点到达时的最小步数

Nodestatus[200*200];

//标记哪些节点是可继续展开(也就是可以形成separator的点)的节点

intM,N;

intlast;

voidFindNext(NodecurStatus)//从curStatus去寻找下面的可用节点

intcurStep=step[curStatus.x][curStatus.y];

intm=curStatus.x+1;

intn=curStatus.y;

if(m==N-1)//如果是已经来到了倒数第二层,由于最后一层肯定只有一个separator的节点。

如果它有两个或以上,可能证明其中一个删去后它仍是一个sep.这样对于每个可用节点,我们直接考虑它是否可以直接向下一步形成seq.

if(chessBox[m][n])

inttempStep=curStep+1;

step[m][n]=tempStep;

else

while(chessBox[m][n]==2)//如果不是倒数第二层,就向左展开可用节点可用的节点满足:

它的正下方有节点存在,如果这个节点是可继续延展的节点。

if(chessBox[m+1][n]==2)

inttempStep=curStep+curStatus.y-n+1;

//更新到达该节点的最小需要的Sep数

if(step[m][n]==0)

(status[last]).x=m;

(status[last]).y=n;

++last;

if(step[m][n]>

tempStep)

--n;

n=curStatus.y+1;

//向右展开节点并更新

while(chessBox[m][n]==2)

inttempStep=curStep+n-curStatus.y+1;

if(step[m][n]==0)

(st

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 成人教育 > 成考

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

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