hdu1010 Tempter of the Bone---DFS+奇偶剪枝

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1010

题目描述:
根据地图,'S'为开始位置,'D'为门的位置,' . '为空地,'X'为墙,不能经过,问:在指定的时间,是否能到达'门'的位置。注意:路不可以重复经过,时间也要刚好是 t ,不能少.

思路:

此处不能用BFS,因为时间要恰好为t,还是得用DFS,不过需要剪枝才能过。

奇偶剪枝:

从一个点到达另外一个点的最短路径长度(时间)可以根据两点坐标求出,路径长度(非最短)与最短路径的长度同奇偶,它们的差一定是偶数!举个例子,就像两个偶数的差差是偶数,两个个数的差也是偶数.

此处还有一个剪枝:
设墙的数目为wall,如果wall + t >= n * m,一定到达不了,因为大于号显然成立,这里主要讨论等号的情况。

比如下图

3 3 1

SDX

XXX

XXX

只需要一步就可以到达,此时wall = 7, t = 1,wall + t < n * m,有可行解,这是由于有S,D的存在,所以如果有可行解,wall的数目一定会比n*m-t要小,等于的话是没有可行解的。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<string>
 6 #include<queue>
 7 using namespace std;
 8 typedef long long ll;
 9 const int INF = 1<<30;
10 const int maxn = 100000;
11 int T, cases;
12 int n, m, k, x1, y1, x2, y2;
13 char Map[10][10];
14 int dir[4][2] = {0,1,1,0,-1,0,0,-1};
15 bool dfs(int x, int y, int time)//到x1, y1点,花费时间time
16 {
17     if(x < 0 || x >= n || y < 0 || y >= m || time > k)return false;
18     //剪枝
19     if(time == k && x == x2 && y == y2)return true;
20     int mintime = k - time - abs(x - x2) - abs(y - y2);
21     if(mintime < 0)return false;//最优性剪枝,当前沿着最优路径走,还是会超过k秒,返回假
22     if(mintime & 1)return false;//奇偶剪枝,相减的时间是奇数的话,在k秒的时候一定到不了终点
23 
24     for(int i = 0; i < 4; i++)
25     {
26         int xx = x + dir[i][0];
27         int yy = y + dir[i][1];
28         if(Map[xx][yy] != 'X')
29         {
30             Map[xx][yy] = 'X';
31             if(dfs(xx, yy, time + 1))return true;
32             Map[xx][yy] = '.';
33         }
34     }
35     return false;
36 }
37 int main()
38 {
39     while(cin >> n >> m >> k && (n + m + k))
40     {
41         int wall = 0;
42         for(int i = 0; i < n; i++)
43         {
44             cin >> Map[i];
45             for(int j = 0; j < m; j++)
46             {
47                 if(Map[i][j] == 'S')x1 = i, y1 = j;
48                 else if(Map[i][j] == 'D')x2 = i, y2 = j;
49                 else if(Map[i][j] == 'X')wall++;
50             }
51         }
52         if(wall + k >= n * m)
53         ///这里是一个特别好的剪枝,如果墙的数目+步数>=n*m,一定不可能完成任务
54         ///重点考虑等号,除了墙还有'S'和'D',墙的数目最多为n*m-k-1(距离,比如k = 1时,S和D相邻,其他都是墙,此时墙的数目最多为n*m-2,满足上述式子)
55         {
56             printf("NO\n");
57             continue;
58         }
59         Map[x1][y1] = 'X';//先设置成X表示该点不能再经过
60         if(dfs(x1, y1, 0))printf("YES\n");
61         else printf("NO\n");
62     }
63 }

 

posted @ 2018-03-30 19:31  _努力努力再努力x  阅读(143)  评论(0编辑  收藏  举报