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

来源:互联网 发布:如何做好淘宝货品 编辑:程序博客网 时间:2024/05/16 11:26

题意是给你大门开启的时间和地点,给你起点,让你写程序判断能否逃脱。


用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;}
记得看小白的时候,刘汝佳就说第二种写法就已经灰常好了。做题的主要目的是过题目,而不是向别人炫你的代码多炫。

打脸。


0 0
原创粉丝点击