Closed Rooms 题解&中文翻译

原题(题目来源暂未确定,如有知情者请留言,谢谢):

Takahashi is locked within a building.

This building consists of H×W rooms, arranged in HH rows and W columns. We will denote the room at the i-th row and j-th column as (i,j). The state of this room is represented by a character A_{i,j}. If A_{i,j}==#, the room is locked and cannot be entered; if A_{i,j}==.,the room is not locked and can be freely entered. Takahashi is currently at the room where A_{i,j}== S, which can also be freely entered.

Each room in the 1-st row, 1-st column, H-th row or W-th column, has an exit. Each of the other rooms (i,j) is connected to four rooms: (i-1,j),(i+1,j),(i,j−1) and (i,j+1).

Takahashi will use his magic to get out of the building. In one cast, he can do the following:

Move to an adjacent room at most KK times, possibly zero. Here, locked rooms cannot be entered.
Then, select and unlock at most KK locked rooms, possibly zero. Those rooms will remain unlocked from then on.
His objective is to reach a room with an exit. Find the minimum necessary number of casts to do so.

It is guaranteed that Takahashi is initially at a room without an exit.

(样例数据附在文章的最下面了!)

中文翻译(找了半天没找到这题的翻译,所以就自己翻译了一下,如有少量错误欢迎吐槽在评论区里)

/*
题面:塔卡哈士(高桥)被锁在了一个建筑内.
这个建筑物包括了H*W个房间,长H宽W.我们将位于长i宽j的房间记作(i,j).如果(i,j)='#',
就说明这个房间被锁住了并且不能被进入;如果这个房间是'.',就认为这个房间没有锁住并
可以进入.塔卡哈士现在在一个没有锁住的房间里.
每一个位于第一排或第一列或第H排或第W列的房间里都有一个出口(指的是离开这座大楼);
每一个不在边缘的房间都与另外四个相邻的房间相邻[就是+1,-1的那四个].
塔卡哈士会使用魔法离开这个大楼,可是他如果想用魔法,就必须这么做:(依次循环执行!) 
	先移动最多M步(每步一个房间),也可以只移动0步(就是不动).这个步骤中,锁住的房间
	不能被进入.然后,选择并解锁至多K个锁定的房间,K也可以为0;这些房间从这时候开始
	就会一直保持被打开的状态;
他所要做的就是离开这栋大楼.求最少需要多少个步骤可以让他离开;
给定的数据保证塔卡哈士最初在一个没有出口的房间内.

给定的数据会满足下列条件: 
	H和W属于[3,800]
	K不会超过H和W的乘积
	每一个房间都只会有'#'和'.'这两种状态;
	给定的地图中必然有且仅有一个'S'(起点),并且保证S不在有出口的房间
输入格式:
	第一行三个整数H,W,K,中间用空格隔开
	接下来H行每行W个字符,每个字符表示一个房间.
输出格式:
	一行一个整数,表示至少需要的步数(每一次循环记为一步); 
*/

注意:这边与经典的问题不同的是这里追求的不是走的步数最短,而是操作数最短.例如你一次如果要开2k+1个房间,就被记录为三步了,而并非2k+1步!

注意到,题目中有说明"保证塔卡哈士最初在一个没有出口的房间内",所以你并不需要特判一开始就出去了的情况,否则还要加一句判断他最开始是否就在边上.

思路都给写代码里了,自己看看吧.

#include<iostream>
#include<queue>
#include<cstdio> 
using namespace std;
int fx[4]={0,1,0,-1},fy[4]={1,0,-1,0},n,m,k,sx,sy;//表示移动方向,长,宽和一次可以解锁的房间数,以及起点横纵坐标 
char s[1010];//输入数组 
bool a[1010][1010],b[1010][1010];//A中True表示可以走,False表示不能走;B记录走过没有走过,True表示走过,False表示没走过
queue<pair<int,int> > q;//需要搜索的点的队列 
queue<int> qs;
int main()
{
	cin>>n>>m>>k;//第一行三个整数,n,m,k; 
    for (int i=1;i<=n;i++)
	{
    	scanf("%s",s+1);
		for (int j=1;j<=m;j++) 
			a[i][j]=!(s[j]=='#');//如果是#就不能走,记为False;否则无论是S还是.都可以走,记为True; 
        for (int j=1;j<=m;j++)
			if (s[j]=='S')//假如这里是起点 
			{
				sx=i;
				sy=j;
			}//用sx和sy记录起点坐标 
    }
    b[sx][sy]=1;//记录起点已经走过了 
    q.push(make_pair(sx,sy));//记录点对 起点 
	qs.push(0);
    while (!q.empty())//只要队列非空, 
	{
        int i_x=q.front().first;//取出队首元素坐标 
        int i_y=q.front().second;
		q.pop();//队首元素出队 
        int i_s=qs.front();//取出队首元素操作数 
		qs.pop();//队首元素出队 
        if (i_s==k)continue;//假如已经打开了k个房间,那么就需要计步数了 
        if (i_x==1||i_x==n||i_y==1||i_y==m)//表示找到了一个可用的出口
        {//因为还没有使用过"魔法"来打开房间,特判这个情况为需要一步来执行 
			cout<<1;
			return 0;
		} 
        for (int i=0;i<4;i++)//枚举四个走路方向 
		{
            int j_x=i_x+fx[i],j_y=i_y+fy[i];//表示下一步的位置 
            if (j_x<1||j_x>n||j_y<1||j_y>m)//如果下一步走出了地图,那么直接排除这个情况 
				continue;
            if (!b[j_x][j_y]&&a[j_x][j_y])//如果这个位置没有被走过并且这个位置还可以走 
			{
                b[j_x][j_y]=1;//那么记录这个位置为走过了 
                q.push(make_pair(j_x,j_y));//将这个位置加入队列 
				qs.push(i_s+1);
            }
        }
    }
    int ans=0x7fffffff;//设置它的初始需要步数为正无穷 (2147483647)
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)//枚举每一个位置 
			if (b[i][j])//如果这里走到过 
			{
            	int cur=(min(min(min(i-1,j-1),n-i),m-j)+k-1)/k+1;//从这里径直出去,+k-k的是为了去除负数 
            	ans=min(ans,cur);//在当前最短路径和上述路径中取最短(注意这里的路径不是真的路径,而是指步数) 
        	}
    cout<<ans<<endl;
    return 0;
}

样例数据

样例输入1

3 3 3
#.#
#S.
###

样例输出1

1

样例说明:可以直接走出去,所以只需要一步

样例输入2

3 3 3
###
#S#
###

样例输出2

2

样例说明:塔卡哈士不能直接走.他需要先解锁房间(1,2),然后他就可以通过(1,2)逃出大楼.所以,他需要两个步骤

样例输入 3

7 7 2
#######
#######
##...##
###S###
##.#.##
###.###
#######

样例输出 3

2

跪求各位看懂了的大佬点个赞!

如果看不懂或者有错误,请在评论区留言/指正,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值