欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

DFS中的奇偶剪枝

程序员文章站 2022-04-26 18:33:40
...

本博客由搜集资料拼凑而成。。。

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

奇偶剪枝

【问题描述:】

给定一个N*M的迷宫以及起点和终点,迷宫中有一些障碍无法穿过,问能否不重复也不停留地在刚好一共走T步出迷宫。

 

【问题分析:】

先来看下这张图片:

DFS中的奇偶剪枝

也就是说当要走偶数步而规定的步数是奇数,或者要走奇数步而规定的步数是偶数,都是不可能到达的,如果要想到达,则要走的步数和规定的步数的奇偶性应该一致。又可知,奇偶性一致的两个数的差或者和都是偶数。(下面有大用处)

 

例如下图:设S点坐标为(sx,sy),D点坐标为(dx,dy),.表示通路,X表示障碍。

S...
....
....
...D

可知从S走到D的最短距离为abs(sx-dx)+abs(sy-dy)

S..X

..XX
.X.X
...D

上面这个迷宫中存在一些障碍,假设当前已走step步,则还剩下t-step步,设当前点到终点的最短距离为abssi - dx+ abs(sj - dy),则两者的奇偶性一定一致的(由上面那段话可知)并且前者一定大于等于后者(剩下要走的步数大于等于该坐标到终点的最短距离),只有这样,才能够到达。也就是tem = t – step – (abssi - dx+ abs(sj - dy))tem >= 0 && tem % 2 == 0.

(http://blog.csdn.net/i1020/article/details/54918472)

其中奇偶剪枝关键便是这句话

ans = t - step - abs(x-ex)-abs(y-ey);
if(ans<0||ans&1)return;
//t为限制的步数,step为已经走过的步数,x,y当前位置
//ex,ey为终点位置

例题:

                                                                                                                       Tempter of the Bone(HDU-1010)

                                                              Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Problem Description

The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze began to shake, and the doggie could feel the ground sinking. He realized that the bone was a trap, and he tried desperately to get out of this maze.

 

The maze was a rectangle with sizes N by M. There was a door in the maze. At the beginning, the door was closed and it would open at the T-th second for a short period of time (less than 1 second). Therefore the doggie had to arrive at the door on exactly the T-th second. In every second, he could move one block to one of the upper, lower, left and right neighboring blocks. Once he entered a block, the ground of this block would start to sink and disappear in the next second. He could not stay at one block for more than one second, nor could he move into a visited block. Can the poor doggie survive? Please help him.

 

 

 

Input

The input consists of multiple test cases. The first line of each test case contains three integers N, M, and T (1 < N, M < 7; 0 < T < 50), which denote the sizes of the maze and the time at which the door will open, respectively. The next N lines give the maze layout, with each line containing M characters. A character is one of the following:

 

'X': a block of wall, which the doggie cannot enter; 

'S': the start point of the doggie; 

'D': the Door; or

'.': an empty block.

 

The input is terminated with three 0's. This test case is not to be processed.

 

 

 

Output

For each test case, print in one line "YES" if the doggie can survive, or "NO" otherwise.

 

 

 

Sample Input

4 4 5

S.X.

..X.

..XD

....

3 4 5

S.X.

..X.

...D

0 0 0 

 

Sample Output

NO

YES 

题意:在一个坐标内,给定起点和终点,问能否恰好在t时刻到达终点。

一开始直接搜索超时,后来各种剪枝还是超时,就单单没有判断奇偶性。判断后又忘记每次初始化访问数组,错了很多次

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int n,m,t;//n,m数组大小,t限制时间
char mp[20][20];//地图
int vis[20][20];//访问数组
int solve;//判断能否到达的变量
int sx,sy,ex,ey;//起点坐标,终点坐标
int dirx[4] = {0,0,1,-1};
int diry[4] = {1,-1,0,0};//方向数组
void dfs(int x,int y,int s){
    int i;
    int xx,yy;
    if(x==ex&&y==ey&&s==t){
        solve = 1;
        return;
    }//恰好符号条件就将solve变成1
    int ans = t-s-abs(x-ex)-abs(y-ey);
    if(ans&1||ans<0)return;//奇偶剪枝
    //if(s>=t)return;
    if(solve==1)return;//如果发现之前已经符合条件了,就直接返回就可以
    for(i = 0; i < 4; i++){
        xx = x + dirx[i];
        yy = y + diry[i];
        if(xx>=0&&xx<n&&yy>=0&&yy<m&&vis[xx][yy]==0&&mp[xx][yy]!='X'){
            vis[xx][yy] = 1;
            dfs(xx,yy,s+1);
            vis[xx][yy] = 0;//普通DFS
        }
    }
}
int main(){
    int i,j;
    while(~scanf("%d%d%d",&n,&m,&t)){
        if(n==0&&m==0&&t==0)break;
        solve = 0;
        for(i = 0; i < n; i++)
            scanf("%s",mp[i]);
        for(i = 0; i < n; i++){
            for(j = 0; j < m; j++){
                if(mp[i][j]=='S'){
                    sx = i;
                    sy = j;
                }
                if(mp[i][j]=='D'){
                    ex = i;
                    ey = j;
                }//记录始末位置
            }
        }
        if(abs(sx-ex)+abs(sy-ey)<=t){//判断如果从起点到终点的最短距离都比t大说明一定到达不了,所以进行判断以优化
            memset(vis,0,sizeof(vis));
            vis[sx][sy] = 1;
            dfs(sx,sy,0);
        }
        if(solve)
            printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}



相关标签: 优化 剪枝