HDOJ 1010 (DFS,剪枝)

Tempter of the Bone

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 128878    Accepted Submission(s): 34798

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

Conclude:

1.DFS奇偶性剪枝,否则超时;

2.多字符串输入只要有空格或者换行,就不能用scanf %c;

3.内外两个回溯;

#include<iostream>
#include<cstring>
using namespace std;
char a[7][7];
int vis[7][7];          //标记能走的位置(除去出界的位置,走过的位置和不能走的位置)
int n,m,t;              //如此就不在递归中判断出界
int x1,y1;
int x,y;
bool flag;
int b[4]={1,-1,0,0};
int c[4]={0,0,1,-1};

int abs(int n)         //发现如果包含cmath头文件中 ,x0,y0,x1,y1等会产生歧义
{
    if(n<0)
       n=-1*n;
    return n;
}

void dp(int k)
{
//    if(x1<0||x1>n||y1<0||y1>m)
//        return;
    if(flag==true)      //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        return;         //!!!!要点:只要有一种 符合条件,就可以结束所有的递归!!!!
    if((abs(x-x1)+abs(y-y1))%2!=(t-k)%2)
        return;         //!!!!要点:由奇偶性剪枝,否则超时 !!!!
    if(abs(x-x1)+abs(y-y1)>t-k)
        return;         //减时操作:最短路径的时间不能超过剩余时间    

    if(k==t)
        {
            if(a[x1][y1]==‘D‘)
                flag=true;
            return;
        }

    vis[x1][y1]=0;
    for(int i=0;i<4;i++)
        {
            if(vis[x1+b[i]][y1+c[i]])
                {
                    x1+=b[i];y1+=c[i];
                    dp(k+1);
                    x1-=b[i];y1-=c[i];
                }   // for循环内回溯,防止对另一种走法产生干扰。
        }
    vis[x1][y1]=1;  // 外部标记回溯 

}

int main()
{
    while(cin>>n>>m>>t)
        {
            int sum=0;
            flag=false;
            if(n==0&&m==0&&t==0)
                break;
            memset(vis,0,sizeof(vis));
            for(int i=0;i<n;i++)
                {
                    scanf("%s",a[i]);   //逐行输入,无&,千万不能scanf( "%c",&a[i][j])
                }                       //scanf %c 能读取空格和换行符。
            for(int i=0;i<n;i++)
                {
                    for(int j=0;j<m;j++)
                        {
                            if(a[i][j]==‘S‘)
                                {
                                    x1=i;
                                    y1=j;
                                }
                            if(a[i][j]==‘D‘)
                                {
                                    x=i;
                                    y=j;
                                    vis[i][j]=1;
                                    sum++;
                                }
                            if(a[i][j]==‘.‘)
                                {
                                    vis[i][j]=1;
                                    sum++;
                                }
                        }
                }
            if(sum<t)    //减时操作:可走方格不能少于固定时间
                {
                    printf("NO\n");
                    continue;
                }
            dp(0);
            if(flag==true)
                printf("YES\n");
            else
                printf("NO\n");
        }
    return 0;
} 
时间: 2024-11-05 18:56:03

HDOJ 1010 (DFS,剪枝)的相关文章

hdu 1010 dfs+剪枝

Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 119601 Accepted Submission(s): 32313 Problem Description The doggie found a bone in an ancient maze, which fascinated him a lot.

HDU 1010 Tempter of the Bone dfs+剪枝

给你一个迷宫一个起点和一个终点,问你能否走T步刚好到达终点,不能重复走,并且只有4个方向 显然这是一个dfs,虽然N最大只有7,但是裸的dfs复杂度还是太高了,因此要进行一些剪枝 1.如果T比图上所有的可走点还要大,肯定是不可行的.这个可以避免dfs整张图. 2.奇偶剪枝,有性质当前点(x,y)到目标点(tx,ty)的所有路径的长度的奇偶性一定和|x-tx|+|y-ty|一样. #include <cstdio> #include <iostream> #include <c

hdu 1010 Tempter of the Bone (DFS+剪枝)

Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 68206    Accepted Submission(s): 18719 Problem Description The doggie found a bone in an ancient maze, which fascinated him a

DFS+剪枝 HDOJ 5323 Solve this interesting problem

题目传送门 1 /* 2 题意:告诉一个区间[L,R],问根节点的n是多少 3 DFS+剪枝:父亲节点有四种情况:[l, r + len],[l, r + len - 1],[l - len, r],[l - len -1,r]; 4 */ 5 #include <cstdio> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 #include <queue> 10

HDOJ 5113 Black And White DFS+剪枝

DFS+剪枝... 在每次DFS前,当前棋盘的格子数量的一半小于一种颜色的数量时就剪掉 Black And White Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others) Total Submission(s): 194    Accepted Submission(s): 50 Special Judge Problem Description In mathematics,

ZOJ 1008 Gnome Tetravex (DFS + 剪枝)

Gnome Tetravex 题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=8 题意:有N*N个方格,每个方格分为上下左右四个部分,每个部分填数字.现在要求重排方块,使得每两个有边相连的方块对应的数字相同. 思路:就是一个简单的搜索,我想了个剪枝,将上下左右四个方向上每个数字对应的是哪几个方块记录下来,但是这个剪枝并没有起很大的作用,还是T了.后来才发现,如果有很多个方块是相同的,会重复搜索,所以需要将相同的方块一起处

UVA 10318 - Security Panel dfs 剪枝

UVA 10318 - Security Panel dfs 剪枝 ACM 题目地址:UVA 10318 - Security Panel 题意: 这题跟点灯的题目很像,点灯游戏选择一盏灯时会让它以及四周的灯改变状态. 但是我们有特殊的开开关技巧,它给出了改变状态的位置,而不是四周都改变. 问你从全部关着变成全部开着的最小开关步骤. 分析: 很明显,在一个位置上点两次或更多次是没有必要的,所以一个位置只有选择与不选择,用dfs即可,但如果暴力所有可能,复杂度是2^25,会超时,所以要剪枝. 由于

Cubes(DFS+剪枝)

题意:给一个数N,求N最少由多少个数的立方构成,并输出这些数. 做法:DFS + 剪枝,剪枝的边界很很很重要! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio.h> int cub[400]; int ans[300]; int tp[300]; int n; int sum = 0x3f3f3f3f; //个数 void dfs(int le

hdu 4109 dfs+剪枝优化

求最久时间即在无环有向图里求最远路径 dfs+剪枝优化 从0节点(自己增加的)出发,0到1~n个节点之间的距离为1,mt[i]表示从0点到第i个节点目前所得的最长路径 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; const

POJ 1564 Sum It Up (DFS+剪枝)

 Sum It Up Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 5820   Accepted: 2970 Description Given a specified total t and a list of n integers, find all distinct sums using numbers from the list that add up to t. For example, if t = 4