hdu 1010 Tempter of the Bone 奇偶剪枝

首先介绍一下什么是奇偶剪枝:

奇偶剪枝

  是数据结构的搜索中,剪枝的一种特殊小技巧。  现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,  


如图所示(“|”竖走,“—”横走,“+”转弯),易证abs(ex-sx)+abs(ey-sy)为此问题类中任意情况下,起点到终点的最短步数,记做step,此处step1=8;  


如图,为一般情况下非最短路径的任意走法举例,step2=14;  step2-step1=6,偏移路径为6,偶数(易证);  故,

t-[abs(ex-sx)+abs(ey-sy)]结果为非偶数(奇数),则无法在t步恰好到达;  返回,false;  反之亦反。

下面是我复制的一些网上的资料没怎么看懂

路径奇偶条件剪枝

仔细观察,从起点到终点的距离的奇偶性决定了所有从起点到终点的可行路径距离的奇偶性!而且这种奇偶相关不随搜索状态的变化而变化。

可以把map看成这样:

010101

101010

010101

101010

010101这里我们用0代表偶数步用1代表积数步

从为0的格子走一步,必然走向为1的格子

从为1的格子走一步,必然走向为0的格子

即:

0->1或1->0不管怎么走必然是奇数步

0->0走1->1不管怎么走必然是偶数步

所以我们可以把其看成最短路径的时候情况用来判断从一点到另一点是用积数步走完还是偶数步走完

很明显,如果起点在0而终点在1那显然要经过奇数步才能从起点走到终点,依次类推,奇偶相同的偶数步,奇偶不同的奇数步
在读入数据的时候就可以判断,并且做剪枝,当然做的时候并不要求把整个矩阵0,1刷一遍,读入的时候起点记为(Si,Sj)终点记为(Di,Dj)判断(Si+Sj)(Di+Dj)的奇偶性就可以了。

所以通过分析,可以得到下面这一判定条件,网上有好多别的式子,但本质是一样的。

if(abs(P.x-Q.x)+abs(P.y-Q.y)%2==T%2)dfs(P);//只需判断一次即可

即如果用xy表示当前所在的迷宫位置时xxyy表示出口时t表示规定的要用多少步走出迷宫count表示已经走过的步数那么t-count是剩下要走的步数那么满足下面的式子才能够在t步正好走出迷宫注易是正好走出哈

abs(xx-x)+abs(yy-y))%2!=(t-count)%2

这个剪枝是很强大的、概率上来说可以减掉一半的Case

下面举例题:

TempteroftheBone

TimeLimit:2000/1000MS(Java/Others)MemoryLimit:65536/32768K(Java/Others)
TotalSubmission(s):24023AcceptedSubmission(s):6616

ProblemDescription

Thedoggiefoundaboneinanancientmaze,whichfascinatedhimalot.However,whenhepickeditup,themazebegantoshake,andthedoggiecouldfeelthegroundsinking.Herealizedthatthebonewasatrap,andhetrieddesperatelytogetoutofthismaze.

ThemazewasarectanglewithsizesNbyM.Therewasadoorinthemaze.Atthebeginning,thedoorwasclosedanditwouldopenattheT-thsecondforashortperiodoftime(lessthan1second).ThereforethedoggiehadtoarriveatthedooronexactlytheT-thsecond.Ineverysecond,hecouldmoveoneblocktooneoftheupper,lower,leftandrightneighboringblocks.Onceheenteredablock,thegroundofthisblockwouldstarttosinkanddisappearinthenextsecond.Hecouldnotstayatoneblockformorethanonesecond,norcouldhemoveintoavisitedblock.Canthepoordoggiesurvive?Pleasehelphim.

Input

Theinputconsistsofmultipletestcases.ThefirstlineofeachtestcasecontainsthreeintegersN,M,andT(1<N,M<7;0<T<50),whichdenotethesizesofthemazeandthetimeatwhichthedoorwillopen,respectively.ThenextNlinesgivethemazelayout,witheachlinecontainingMcharacters.Acharacterisoneofthefollowing:

'X':ablockofwall,whichthedoggiecannotenter;
'S':thestartpointofthedoggie;
'D':theDoor;or
'.':anemptyblock.

Theinputisterminatedwiththree0's.Thistestcaseisnottobeprocessed.

Output

Foreachtestcase,printinoneline"YES"ifthedoggiecansurvive,or"NO"otherwise.

SampleInput

445S.X...X...XD....345S.X...X....D000

SampleOutput

NOYES

我的代码:

#include<stdio.h>

#include<string.h>

#include<math.h>

intn,m,t,s_i,s_j,d_i,d_j;

chara[10][10];

intflag[10][10];

intans,cnt;

voiddfs(inti,intj,intti)

{

if(ans==1)return;

if(i<=0||j<=0||i>n||j>m)return;

if(ti>t)return;

if(a[i][j]=='X')return;

//if(t-ti<abs(d_i-i)+abs(d_j-j))return;//剩余最短路径所需时间如果比剩余时间大则return

//上面那句话加上可以更加缩短时间

if(flag[i][j]==1)return;

if(t==ti&&i==d_i&&j==d_j){ans=1;return;}

if(abs(t-ti)%2!=(abs(d_i-i)+abs(d_j-j))%2)return;//奇偶剪枝如果少了这句就会超时所以

//这句话的作用很大要好好体会

flag[i][j]=1;

dfs(i-1,j,ti+1);

dfs(i+1,j,ti+1);

dfs(i,j+1,ti+1);

dfs(i,j-1,ti+1);

flag[i][j]=0;

}

intmain()

{

inti,j;

while(scanf("%d%d%d",&n,&m,&t))

{

getchar();

cnt=0;

if(n==0&&m==0&&t==0)return0;

for(i=1;i<=n;i++)

{

for(j=1;j<=m;j++)

{

scanf("%c",&a[i][j]);

if(a[i][j]=='S'){s_i=i;s_j=j;}

else

if(a[i][j]=='D'){d_i=i;d_j=j;cnt++;}//一开始这里的cnt++忘了加了导致错了//好多次浪费了好多时间所以以后做题小细节一定要注意到不要忽视任何一个小地

//方

elseif(a[i][j]=='.')cnt++;

}

getchar();

}

if(cnt<t){printf("NO\n");continue;}

memset(flag,0,sizeof(flag));

ans=0;

dfs(s_i,s_j,0);

if(ans==1)printf("YES\n");

elseprintf("NO\n");

}

return0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值