2020.01.18【NOIP提高组】模拟B 组——总结——探险者拉罗

本文介绍了一个关于迷宫探险的问题,拉罗需要从入口到达尽可能多的藏金点并找到出口,途中可以使用潜行技能避开怪物。迷宫大小为N×N,最多有16个藏金点,拉罗最多连续潜行M个有怪物的格子。问题采用状态转移的动态规划方法解决,通过BFS求解起点、终点、藏金点间的最短距离,并找出访问最多藏金点的最短潜行时间。

晚上十点十分才a了这题,太难了。

Description

探险者拉罗最近发现了一个远古的宫殿,该宫殿可以表示为N×N个格子的迷宫,其中有一个格子是入口(用E表示),一个格子是出口(用X表示),有若干个格子是藏金点(用G表示),有若干个格子是障碍物(用#表示),其他格子都有怪物在里面(用-表示)。拉罗由入口开始探险,希望到达尽量多的藏金点,然后由出口离开。当然,障碍物是不能通过的。而且,由于那些远古的怪物异常凶狠,一旦被它们发现,拉罗必死无疑。幸运的是,经过多年的磨练,拉罗练就了一身非凡的本领,其中有一招叫做潜行,当她使用潜行经过有怪物的格子时,怪物是不会发现她的。不幸的是,她不能连续潜行太久,不然就会窒息,准确来说,她最多可以连续潜行着经过M个有怪物的格子。现在拉罗手头上已经有整个迷宫的地图,她需要规划出一条完整的行动路线,希望访问到尽量多的藏金点,在保证访问最多个藏金点的基础上,她还希望潜行的总时间最少(走一格为1个单位时间)。你可以帮助她吗?
  注意,每个格子都可以多次被访问,同一个怪物格子每访问一次潜行总时间就加1,但同一个藏金点无论被访问多少次都只能算作一个,另外,即使走到了出口她也可以选择先不出去而继续走到其他点。数据保证拉罗可以由出口离开。

Input

输入第一行是两个整数N(1 <= N <= 100)和M(1 <= M <= 200),分别表示迷宫的边长和拉罗最多可以连续潜行的格子数。
  接下来N行每行一个字符串,每个字符串恰好有N个字符,字符串仅包含’E’、’X’、’G’、’#’、’-’。保证有且仅有一个E,有且仅有一个X,不超过16个G。

Output

输出一行,包含两个整数,分别是可以访问到的最多的藏金点数和在访问最多藏金点的基础上所需的最少的潜行总时间,两个整数之间用一个空格隔开。

Sample Input

3 1
E-G
#G-
–X

Sample Output

2 3

Hint

【数据范围】
  对于50%的数据,藏金点G不超过8个。

赛时

一看金子<=16,就知道是我不会的状压dp

正解

实际上就是状压dp

我们先将起点,终点,和金子压到所谓的二进制中。那么1代表这个点到过,0则代表没到过。这三者加一起才18,所以完全装得下。

f[s][i]表示s这个状态下到i时的最小潜行时间,那么方程即是:f[s’][j]=min(f[s’][j],f[s][i]+dis[i][j]);(s’代表更新的一个状态,dis是求每每(起点,终点,和金子)之间的最短距离)

可能还会不懂,没事,一步步来

首先我们将起点,终点和金子之间的最小距离用bfs求出来。

代码
void bfs(int x,int y){
   
   
	memset(vis,0,sizeof(vis));//是否访问过
	memset(d,0,sizeof(d));//数组模拟队列
	t=1;h=0;//头与尾
	d[t][0]=x,d[t][1]=y,d[t][2]=0,d[t][3]=0;
		//初值,0为坐标x,1为坐标y,2为当前潜行时间,3为一共潜行时间
	vis[x][y]=1;//起点访问过
	while(h++<t){
   
   
		for(int i=0;i<4;i++){
   
   
			nx=d[h][0]+xx[i];ny=d[h][1]+yy[i];//新坐标
			if(nx<1||nx>n||ny<1||ny>n||vis[nx][ny]||bz[nx][ny]==3)continue;
				//边界,我设bz数组为x,y位置的情况,1为起点和终点,2为
				//金子,3为障碍物,0为怪兽
			if(bz[nx][ny]==1||bz[nx][ny]==2){
   
   //若是起点,终点,或金子
				now=0,sum=d[h][3];//now为当前潜行时间,这时为0
								  //sum为当前总时间,不变
				dis[num[x][y]][num[nx][ny]]=dis[num[nx][ny]][num[x]
				[y]]=min(dis[num[x][y]][num[nx][ny]],sum);
					//num来存起点,终点,或金子是第几个,这里遇到个三个玩意之一
					//更新一下最短路径
			}
			else if(d[h][2]+1>m)continue;//潜行时间超标
			else now=d
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值