您的位置:首页 > 其它

hdu 1010 Tempter of the Bone(dfs + 奇偶剪枝)

2014-06-12 19:26 423 查看
题意是给你大门开启的时间和地点,给你起点,让你写程序判断能否逃脱。

用dfs很好想到,但是会TLE。

所以学了一个剪枝的手法,叫奇偶剪枝。

ps。我把abs函数写错了 debug了好久。摔。

某大神的分析:

(1)题意很清楚,就是在t时间正好达到出口,使用的是深搜+剪枝

(2)关于深搜不再赘述,这里的深搜并不麻烦,麻烦的是剪枝

(3)一开始我也一直的超时,上网查了别人的解释才知道这道题需要剪枝,一个以前没见过的剪枝。。。。

奇偶剪枝(转自百度百科):

是数据结构的搜索中,剪枝的一种特殊小技巧。   

现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,   

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

s
+
|+
|
+e
如图,为一般情况下非最短路径的任意走法举例,step2=14;   

step2-step1=6,偏移路径为6,偶数(易证);   

故,若t-[abs(ex-sx)+abs(ey-sy)]结果为非偶数(奇数),则无法在t步恰好到达;   

返回,false;   

反之亦反。

(4)应用到这道题时,t-abs(r-end_x)-abs(c-end_y)应该与step的奇偶性相同。。所以t-dep-abs(r-end_x)-abs(c-end_y)应该为偶数。(奇-奇=偶;偶-偶=偶)。

代码:效率不高。

#include<stdio.h>
const int MaxN = 10;

char map[MaxN][MaxN];
bool vis[MaxN][MaxN];
int dir[][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

int N, M, T;
int endx, endy;//奇偶剪枝

int abs(int a, int b)//debug
{
int tmp = a - b;
if(tmp >= 0)
return tmp;
else
return -tmp;
}

bool dfs(int x, int y, int dep)
{
if(map[x][y] == 'D' && dep == T)
return true;
if(dep >= T)
return false;
//奇偶剪枝
int tmp = T - dep - abs(x, endx) - abs(y, endy);
//printf("---%d---\n", tmp);
if(tmp < 0 || tmp % 2 != 0)
return false;
for(int i = 0; i < 4; i++)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(nx < 1 || nx > N || ny < 1 || ny > M)//debug
continue;
if(map[nx][ny] == 'X' || vis[nx][ny])
continue;
vis[nx][ny] = true;
if(dfs(nx, ny, dep + 1))
return true;
vis[nx][ny] = false;
}
return false;
}

int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif // LOCAL
while(scanf("%d%d%d", &N, &M, &T)!=EOF)
{
if(N == 0 && M == 0 && T == 0)
break;
getchar();
//debug;
for(int i = 0; i < MaxN; i++)
for(int j = 0; j < MaxN; j++)
vis[i][j] = false;

int starx, stary;
for(int i = 1; i <= N; i++)
{
for(int j = 1; j <= M; j++)
{
scanf("%c", &map[i][j]);
//vis[i][j] == false; debug
if(map[i][j] == 'S')
{
starx = i;
stary = j;
}
if(map[i][j] == 'D')
{
endx = i;
endy = j;
}
}
getchar();
}
/*for(int i = 1; i <= N; i++)
{
for(int j = 1; j <= M; j++)
{
printf("%c", map[i][j]);
}
printf("\n");
}*/
vis[starx][stary] = true;
if(dfs(starx, stary, 0))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}


为什么abs会错捏。

这是第一次的写法,据扯是太文艺了所以错了。

int abs(int a, int b)
{
if(a < b)
a = a + b - (b = a);
return a - b;
}


这是朴素写法。。。

int abs(int a, int b)
{
int t;
if(a < b)
{
t = a;
a = b;
b = t;
}
return a - b;
}
记得看小白的时候,刘汝佳就说第二种写法就已经灰常好了。做题的主要目的是过题目,而不是向别人炫你的代码多炫。

打脸。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: