ACM必做50题的解题搜索文档格式.docx
- 文档编号:18441065
- 上传时间:2022-12-16
- 格式:DOCX
- 页数:26
- 大小:24.48KB
ACM必做50题的解题搜索文档格式.docx
《ACM必做50题的解题搜索文档格式.docx》由会员分享,可在线阅读,更多相关《ACM必做50题的解题搜索文档格式.docx(26页珍藏版)》请在冰豆网上搜索。
&
(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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ACM 50 解题 搜索