首页 > 其他分享 >(hdu step 4.3.1)Tempter of the Bone(在特定的时间约束下,判断是否能够从起点达到终点)

(hdu step 4.3.1)Tempter of the Bone(在特定的时间约束下,判断是否能够从起点达到终点)

时间:2023-05-07 22:06:06浏览次数:43  
标签:map hdu 4.3 剪枝 int Tempter sj si 节点


题目:


Tempter of the Bone

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

Total Submission(s): 1134 Accepted Submission(s): 379

 

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 5S.X...X...XD....3 4 5S.X...X....D0 0 0



 

Sample Output



NOYES



 

Author


ZHANG, Zheng


 

Source


ZJCPC2004


 

Recommend


JGShining


 



题目分析:

                “判断是否能够从起点达到终点”,这种题用BFS就能轻松搞定。然后这道题的特点就在于“在指定时间的约束下”。那么这时候我们可以使用DFS来做。   本来想自己写一下想法的。但是发现网上有人写的比我将要写的详细多了。所以投一下懒,用一下别人的总结。



  1. 1010 temp of the bone

  2. sample input:
  3. 4 4 5
  4. S.X.
  5. ..X.
  6. ..XD
  7. ....

  8. 问题:
  9. (1):
  10. 在发现当前节点无法到达时,这点弹出栈,并且把这点的标记重新刷为'.'

  11. (2):
  12. 如何在dfs中既要保证到达又要使时间正好呢?? 在函数中通过这种形式实现:

  13. dfs(int si,int sj,int cnt) 就是用cnt来记录当时的时间,并且在

  14. if( si==di && sj==dj && cnt==t )
  15.     {
  16.         escape = 1;
  17.         return;
  18.     }

  19. 的时候 即当前点到达了终点并且时间恰好等于题目所给限制时间时,跳出
  20. 并且escape标记为真

  21. (3):
  22. 如何让一个点有顺序地遍历它四周地能到达的点呢??
  23. 聪明并且简短的方法是设施一个dir[4][2] 数组 控制方向
  24. 并且设置它的值为dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}};

  25. 遍历的时候用for(i:0->4)就非常方便了

  26. (4):
  27. 千万要注意的是节点越界的情况, dfs(int si,int sj,int cnt)的时候一定要把 si, sj 控制在给你的矩阵内 在后面会提到一个我的列子 就是因为访问了[0, -1]的位置导致了其

  28. 他数据被更改

  29. (5):
  30. 读入矩阵的时候,可以采用for(i = 1; i <= N; i++)
  31.                for(j = 1; j <= M; j++)
  32.                 scanf("%c", &map[i][j]);       

  33. 的方法,好处在于可以控制和计算每一个读入的数据,坏处是调试的时候对矩阵的观察不太方便,而且好像还会有错误,在2102"A计划"用这种方法读入数据时好像就会wa,

  34. 另一种方法是for(i = 0; i < N; i++) gets(map[i]);
  35. 这样读入的数据在调试观察的时候十分方便 gets()读入的默认为字符串,在vc调试的时候是显式的 可以直接观察矩阵 缺点是对矩阵中各个数据的计算和控制无法实现,需要读完后再遍历一遍

  36. (6)
  37. 能用bfs还是尽量用bfs 我不会bfs.... dfs的递归在调试的时候不是很方便,而且bfs要比dfs快,调试也要方便,因为它没有递归

  38. (7)
  39. 关于剪枝,没有剪枝的搜索不太可能,这题老刘上课的时候讲过两个剪枝,一个是奇偶剪枝,一个是路径剪枝

  40. 奇偶剪枝:
  41. 把矩阵标记成如下形式:
  42. 0,1,0,1,0
  43. 1,0,1,0,1
  44. 0,1,0,1,0
  45. 1,0,1,0,1
  46. 很明显,如果起点在0 而终点在1 那显然 要经过奇数步才能从起点走到终点,依次类推,奇偶相同的偶数步,奇偶不同的奇数步
  47. 在读入数据的时候就可以判断,并且做剪枝,当然做的时候并不要求把整个矩阵0,1刷一遍,读入的时候起点记为(Si,Sj) 终点记为(Di,Dj) 判断(Si+Sj) 和 (Di+Dj) 的奇偶性就可以了

  48. 路径剪枝:
  49. 矩阵的大小是N*M 墙的数量记为wall 如果能走的路的数量 N*M - wall 小于时间T,就是说走完也不能到总的时间的,这显然是错误的,可以直接跳出了

  50. 课件里面给过这题的标程,在dfs的过程中有个没提到的剪枝,就是记录当前点到终点的最短路,如果小于剩余的时间的话,就跳出
  51. 这个剪枝我觉得更科学,它毕竟是动态的么,标程里面是这么写的:
  52. temp = (t-cnt) - abs(si-di) - abs(sj-dj);
  53. if( temp<0 || temp&1 ) return;

  54. 其中求当前点到终点的最短路是这样 abs(si-di) - abs(sj-dj) 这个就比较粗糙了 明显没有考虑到碰到墙要拐弯的情况
  55. 那求最短路有没有什么好办法呢?

  56. 我曾经想到过用 Dijkstraq求最短路的 ,明显大才小用,在论坛里看到一个方法觉得可以用在这里
  57. 给定下例:

  58. S.X.
  59. ..X.
  60. ..XD
  61. ....

  62. 每个点到终点的最短路是不是这样呢:

  63. S6X2
  64. 65X1
  65. 54XD
  66. 4321

  67. 这怎么求呢??从终点开始遍历整个数组,终点是0,它周围的点都+1,墙就不计数,依次类推,就能求得这个矩阵的一个最短时间矩阵,在dfs的时候比较当前点到终点的最短路,如果大于剩余时间的话就跳出

  68. 这个方法的预处理还是非常快的,我没有用过,但是感觉会非常有用处.

  69. (8)
  70. 在做这题的时候,我碰到过一个神奇的事情,在程序运行至下面代码时

  71. if( map[ si+dir[i][0] ][ sj+dir[i][1] ] != 'X')           
  72.     map[ si+dir[i][0] ][ sj+dir[i][1] ] = 'X';

  73. T被改变了!! 这丝毫和T没有关系啊,怎么改变T的值呢??

  74. 原来在起点map[0][0]进入时,我没有注意到map[ si+dir[i][0] ][ sj+dir[i][1] ] 实际做的是map[0][-1] = 'X'; 很危险的一个赋值,书本上千万次强调的东西让我碰上了,这个地方我找了很久,因此我觉得有必要单独列出来提醒自己


代码如下:


/*
 * a.cpp
 *
 *  Created on: 2015年2月24日
 *      Author: Administrator
 */


#include <iostream>
#include <cstdio>

using namespace std;

const int maxn = 9;
char map[maxn][maxn];//地图矩阵.用于存储地图的情况

int n;//行数
int m;//列数
int t;//目标时间

int x1,y1;//起点
int x2,y2;//终点

int dir[4][2]={//方向矩阵
		{1,0},
		{-1,0},
		{0,1},
		{0,-1}
};

/**
 * 判断下一步是否合法
 */
bool check(int x,int y){
	if( x < 0 || x >= n || y <0 || y >= m){//如果坐标越界
		return false;//则表明下一步不合法
	}

	return true;//否则下一步合法
}


/**
 * DFS。
 * si:当前结点的行数
 * sj:当前节点的列数
 * cnt:到达(si,sj)是所用的时间
 */
bool dfs(int si,int sj,int cnt){
	if(si == x2 && sj == y2 && cnt == t){//如果在指定时间内到达目标点
		return true;//返回true
	}

	/**
	 * 如果当前结点越界。这个判断是不需要的。
	 * 加了还可能超时。因为是否越界的判断在产生下一节点的时候就已经做了
	 */
//	if(check(si,sj) == false){
//		return false;
//	}

	/**
	 *
	 * t-cnt:表示剩余时间
	 * abs(x2-si) + abs(y2-sj):从当前节点道目标节点所需要的时间
	 */
	int temp = (t - cnt) - (abs(x2-si) + abs(y2-sj));
	//最短路径剪枝
	if(temp < 0){//如果剩余时间不足以到达目标节点
		return false;//返回false,表示这条路径不成功
	}

	//奇偶剪枝
	if(temp&1){
		return false;
	}

	int i;
	for(i = 0 ; i < 4 ; ++i){//遍历当前节点的相邻结点
		int tempi = si+dir[i][0];//计算下一节点的坐标
		int tempj = sj+dir[i][1];

		if(check(tempi,tempj) == false){//如果计算出来的下一届点的坐标不合法
			continue;//则跳过这一结点,计算下一结点
		}

		if(map[tempi][tempj] != 'X'){//如果当前节点不是墙壁
			map[tempi][tempj] = 'X';//江当前节点设置为墙壁
			bool flag = dfs(tempi,tempj,cnt+1);//沿着这一节点往下搜

			if(flag == true){//如果这一条路径可行
				return true;//则返回true.表示目标节点可以到达
			}
			//当知心以下代码的时候表示通过这一节点无法到达目标节点

			map[tempi][tempj] = '.';//拿奖当前节点重新设置成'.'可用状态
		}
	}

	return false;//如果经过上面都无法找到一条路径.那么到现在的时候就已经表明目标节点无法到达
}


int main(){
	while(scanf("%d%d%d",&n,&m,&t) != EOF,n){
		int i;
		int j;
		for(i = 0 ; i < n ; ++i){
			cin >> map[i];
		}

		int wall = 0;//用于包村墙壁的数量

		for(i = 0 ; i < n ; ++i){
			for(j = 0 ; j < m ; ++j){
				if(map[i][j] == 'S'){//记录起点的位置
					x1 = i;
					y1 = j;
				}else if(map[i][j] == 'D'){//记录终点的位置
					x2 = i;
					y2 = j;
				}else if(map[i][j] == 'X'){//统计墙壁的数量
					wall++;
				}
			}
		}

		//路径剪枝
		int nums = n*m - wall;//计算可走的步数
		if(nums < t){//如果可走的步数<指定的时间
			printf("NO\n");//那么表明路已经走完了也还没有达到指定时间.name返回false.表示没有这样的一条路径
			continue;
		}

		map[x1][y1] = 'X';//奖起点设置为墙壁'x'
		bool result = dfs(x1,y1,0);//从起点开始遍历

		if(result == true){//如果resultweighttrue,表明有这么一条路径
			printf("YES\n");
		}else{
			printf("NO\n");//否则表明没有这样一条路径
		}
	}

	return 0;
}








标签:map,hdu,4.3,剪枝,int,Tempter,sj,si,节点
From: https://blog.51cto.com/u_5290007/6252588

相关文章

  • (hdu step 3.2.6)Monkey and Banana(在第一关键字有序的情况下,根据第二关键字求最长
    题目:MonkeyandBananaTimeLimit:2000/1000MS(Java/Others)MemoryLimit:65536/32768K(Java/Others)TotalSubmission(s):720AcceptedSubmission(s):455 ProblemDescriptionAgroupofresearchersaredesigninganexperimenttotesttheIQof......
  • (hdu step 3.2.7)免费馅饼(数塔变形:求所能接到馅饼的最大数)
    题目:免费馅饼TimeLimit:2000/1000MS(Java/Others)MemoryLimit:65536/32768K(Java/Others)TotalSubmission(s):1207AcceptedSubmission(s):508 ProblemDescription都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼。......
  • hdu 1599 find the mincost route(无向图的最小环:求从一个点遍历所有节点以后回到原点
    题目:findthemincostrouteTimeLimit:1000/2000MS(Java/Others)    MemoryLimit:32768/32768K(Java/Others)TotalSubmission(s):2801    AcceptedSubmission(s):1115ProblemDescription杭州有N个景区,景区之间有一些双向的路来连接,现在8600想找一条旅游......
  • 6.4.3(3) 余弦定理、正弦定理的应用
    \({\color{Red}{欢迎到学科网下载资料学习}}\)[【基础过关系列】高一数学同步精品讲义与分层练习(人教A版2019)](https://www.zxxk.com/docpack/2921718.html)\({\color{Red}{跟贵哥学数学,so\quadeasy!}}\)必修第二册同步巩固,难度2颗星!基础知识解三角形一般地,三角形的......
  • 6.4.3(2) 正弦定理
    \({\color{Red}{欢迎到学科网下载资料学习}}\)[【基础过关系列】高一数学同步精品讲义与分层练习(人教A版2019)](https://www.zxxk.com/docpack/2921718.html)\({\color{Red}{跟贵哥学数学,so\quadeasy!}}\)必修第二册同步巩固,难度2颗星!基础知识正弦定理(1)内容在一......
  • 6.4.3(1) 余弦定理
    \({\color{Red}{欢迎到学科网下载资料学习}}\)[【基础过关系列】高一数学同步精品讲义与分层练习(人教A版2019)](https://www.zxxk.com/docpack/2921718.html)\({\color{Red}{跟贵哥学数学,so\quadeasy!}}\)必修第二册同步巩固,难度2颗星!基础知识解三角形一般地,三角形的......
  • 建民打卡日记4.30
    一、问题描述大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图所示:现要求你编写一个稳赢不输的程序,根据对方的出招,给出对应的赢招。但是!为了不让对方输得太惨,你需要每隔K次就让一个平局。二、流程设计1.录入平局间隔次数,定义计数器;2.End结束游戏,break;3.若......
  • django.core.exceptions.ImproperlyConfigured: mysqlclient 1.4.3 or newer is requi
     1、在项目中__init__.py中这个报错原因,python3.5以上版本不支持这种方式frompymysqlimportinstall_as_MySQLdbinstall_as_MySQLdb()解决:importpymysqlpymysql.version_info=(1,4,3,"final",0)#指定了pymysql的版本:1.4.3,按照你版本修改pymysql.install_as_MySQLdb()......
  • 4.3.2 Nginx负载均衡器配置
    作者:田逸(formyz)存在两个项目,一个是Web服务集群,另一个是Python集群。将这两个集群置于同一个负载均衡器之下,有效利用资源。为了便于开展工作,先把资源分配列举出来,如表4-3所示。表4-3名称说明Web服务VIP地址及TCP端口172.16.35.188:80自定义Python服务地址及TCP端口172.16.35.189:10......
  • 上周热点回顾(4.24-4.30)
    热点随笔:· 服务器出现了一个新软件,一帮大佬吵起来了! (轩辕之风)· 【故障公告】被放出的Bing爬虫,又被爬宕机的园子 (博客园团队)· [MAUI]模仿网易云音乐黑胶唱片的交互实现 (林晓lx)· VueHub:我用ChatGPT开发的第一个项目,送给所有Vue爱好者 (DOM哥)· .NETWeb......