计蒜客-蒜头君回家-思路与注意点--补充《算法笔记》

蒜头君回家

题目图片

思路

本题思路和考虑方式比较特别,值得分享一下。
根据题意,需要先拿到钥匙再到达终点,求出最少的步数。

个人思路

首先最容易想到的是bfs的层数即为最少步数,但要注意一个易错点(个人思路犯的错误),并不是现在起点找到最近的钥匙,再拿着钥匙去终点,这是典型的贪心思想。这并只能保证拿到钥匙的步数最少,而钥匙与终点之间的距离没有考虑到。

本题思路

应该从全局着手,要知道行走的路程是可逆的,即起点与终点到各个钥匙的路程和各个钥匙回到起点终点的路程可逆,因此分别从起点和终点做一次bfs,把到达各个钥匙所用的步数存储起来,最后找出最小的步数即可

代码

代码有些冗余,主要是不想使用三维数组

#include<bits/stdc++.h>
using namespace std;
int n, m, minpath = 0x3fffffff;
char mp[2005][2005];
bool inq[2005][2005], reverinq[2005][2005];//正向inq,反向reverinq
int keys[2005][2005];//拿不同钥匙需要走的步数
int dir[4][2] = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}}; 
int sx, sy, ex, ey, cntkeys; 
struct Node
{
    int x;
    int y;
    int step;
    Node(){}
    Node(int xx, int yy, int ss)
    {
        x = xx;
        y = yy;
        step = ss;
    }
};
queue<Node> q, reverq;
//坐标xy
void bfs1(int x, int y)
{
	int cnt = 0;
    Node node = Node(x, y, 0);
    q.push(node);
    inq[x][y] = true;
    while(!q.empty())
    {
    	Node top = q.front();
    	q.pop();
    	if(mp[top.x][top.y] == 'P')
    	{
    		cnt++;
    		keys[top.x][top.y] = top.step;
    	}
    	if(cnt == cntkeys)
    		break;
    	for(int i = 0; i < 4; i++)
    	{
    		int tx = top.x + dir[i][0];
    		int ty = top.y + dir[i][1];
    		if(tx >= 0 && tx < n && ty >= 0 && ty < m && mp[tx][ty] != '#' && !inq[tx][ty])
    		{
    			inq[tx][ty] = true;
    			Node temp = Node(tx, ty, top.step + 1);
    			q.push(temp);
    		}
    	}
	}
}
void bfs2(int x, int y)
{
	int cnt = 0;
    Node node = Node(x, y, 0);
    reverq.push(node);
    reverinq[x][y] = true;
    while(!reverq.empty())
    {
    	Node top = reverq.front();
    	reverq.pop();
    	if(mp[top.x][top.y] == 'P')
    	{
    		cnt++;
    		keys[top.x][top.y] += top.step;
    		minpath = min(minpath, keys[top.x][top.y]);
    	}
    	if(cnt == cntkeys)
    		break;
    	for(int i = 0; i < 4; i++)
    	{
    		int tx = top.x + dir[i][0];
    		int ty = top.y + dir[i][1];
    		if(tx >= 0 && tx < n && ty >= 0 && ty < m && mp[tx][ty] != '#' && !reverinq[tx][ty])
    		{
    			reverinq[tx][ty] = true;
    			Node temp = Node(tx, ty, top.step + 1);
    			reverq.push(temp);
    		}
    	}
	}
}
int main()
{
    scanf("%d %d", &n, &m);
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < m; j++)
        {
            scanf(" %c", &mp[i][j]);
            if(mp[i][j] == 'S')
            {
            	sx = i;
            	sy = j;
            }
            else if(mp[i][j] == 'T')
            {
            	ex = i;
            	ey = j;
            }
            else if(mp[i][j] == 'P')
            {
            	cntkeys++;//统计钥匙的个数
            }
        }
    }
    bfs1(sx, sy);
    bfs2(ex, ey);
    printf("%d\n", minpath);
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值