HDU 5040 Instrusive 【BFS+优先队列】

本文探讨了一种结合BFS算法和优先队列解决迷宫逃脱问题的方法,通过记录摄像头状态和预处理照射情况,实现了从起点到终点的最短路径寻找,特别关注了状态记录和判断条件的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:你需要从M走到T,‘ # ’表示障碍不能走,‘ . ’表示道路,路上有W E N S的四种摄像头,每一秒钟会顺时针旋转一次,你拥有一个纸盒子(藏在纸盒子里不会被看到),你可以藏在纸盒子走需要花费3s,藏在纸盒子里原地不动1s,移动一步1s.到达T点所需要的时间。

思路:很容易想到  bfs+优先队列,如何记录状态呢,摄像头旋转周期的4,到达某一个点摄像头的状态只有4种状态,所以我们用VIS【X】【Y】【T%4】表示状态,我们还可以预处理摄像头照射的情况,然后就是bfs判断条件放入队列。

吐槽:什么鬼题意,揣摩了半天都没读懂。

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const ll mod=998424353;
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;

int n;
int vis[505][505][4];

int dic[4][2]= {1,0,-1,0,0,1,0,-1};

int num[5]={1,2,4,8,0};

int range[505][505];    ///记录位置被照射的情况
/// 二进制表示  1010表示t%4==3 和  t%4==1 被照射

char maps[505][505];

struct node
{
    int x;
    int y;
    int t;
    bool friend operator<(node a,node b)
    {
        return a.t>b.t;
    }
};

int win(int x,int y)
{
    if(x>=1&&x<=n&&y>=1&&y<=n&&maps[x][y]!='#')
        return 1;
    return 0;
}

int judge(int x,int y,int t)
{
    if(range[x][y]&num[t%4])    ///判断当前位置当前时刻是否被照射
        return 0;
    return 1;
}

int bfs(int sx,int sy)
{
    priority_queue<node>q;
    memset(vis,0,sizeof(vis));
    vis[sx][sy][0]=1;
    q.push(node{sx,sy,0});
    while(!q.empty())
    {
        node now=q.top();
        q.pop();
        if(maps[now.x][now.y]=='T')
            return now.t;
        if(!vis[now.x][now.y][(now.t+1)%4])     ///在原地停留
        {
            vis[now.x][now.y][(now.t+1)%4]=1;
            q.push(node{now.x,now.y,now.t+1});
        }
        for(int i=0; i<=3; i++)
        {
            int dx=now.x+dic[i][0];
            int dy=now.y+dic[i][1];
            if(win(dx,dy))  ///下一个位置是否能够走
            {
                ///只走一步
                if(maps[dx][dy]!='W'&&maps[dx][dy]!='E'&&maps[dx][dy]!='N'&&maps[dx][dy]!='S')  ///下一个位置不是摄像头
                {
                    ///下一个位置未标记,并且  当前位置和下一个位置  没被监控
                    if(!vis[dx][dy][(now.t+1)%4]&&judge(now.x,now.y,now.t)&&judge(dx,dy,now.t))
                    {
                        ///比如t=0->t=1   (0,1],初始为S的摄像头,旋转过程中会一直监控(x+1,y)这一点
                        ///当t=1才监控到(x,y-1)
                        vis[dx][dy][(now.t+1)%4]=1;
                        q.push(node{dx,dy,now.t+1});
                    }
                }
                ///藏在盒子里走
                if(!vis[dx][dy][(now.t+3)%4])
                {
                    vis[dx][dy][(now.t+3)%4]=1;
                    q.push(node{dx,dy,now.t+3});
                }
            }
        }
    }
    return -1;
}

int main()
{
    int t;
    int sx,sy;
    scanf("%d",&t);
    for(int u=1; u<=t; u++)
    {
        memset(range,0,sizeof(range));
        scanf("%d",&n);
        for(int x=1; x<=n; x++)
        {
            scanf("%s",maps[x]+1);
            for(int y=1; y<=n; y++)
            {
                if(maps[x][y]=='W')
                {
                    range[x][y-1]|=num[0];
                    range[x-1][y]|=num[1];
                    range[x][y+1]|=num[2];
                    range[x+1][y]|=num[3];
                    range[x][y]=15;
                }
                else if(maps[x][y]=='E')
                {
                    range[x][y+1]|=num[0];
                    range[x+1][y]|=num[1];
                    range[x][y-1]|=num[2];
                    range[x-1][y]|=num[3];
                    range[x][y]=15;
                }
                else if(maps[x][y]=='N')
                {
                    range[x-1][y]|=num[0];
                    range[x][y+1]|=num[1];
                    range[x+1][y]|=num[2];
                    range[x][y-1]|=num[3];
                    range[x][y]=15;
                }
                else if(maps[x][y]=='S')
                {
                    range[x+1][y]|=num[0];
                    range[x][y-1]|=num[1];
                    range[x-1][y]|=num[2];
                    range[x][y+1]|=num[3];
                    range[x][y]=15;
                }
                else if(maps[x][y]=='M')
                    sx=x,sy=y;
            }
        }
        printf("Case #%d: %d\n",u,bfs(sx,sy));
    }
    return 0;
}

 

对于HDU4546问题,还可以使用优先队列(Priority Queue)来解决。以下是使用优先队列的解法思路: 1. 首先,将数组a进行排序,以便后续处理。 2. 创建一个优先队列(最小堆),用于存储组合之和的候选值。 3. 初始化优先队列,将初始情况(即前0个数的组合之和)加入队列。 4. 开始从1到n遍历数组a的元素,对于每个元素a[i],将当前队列中的所有候选值取出,分别加上a[i],然后再将加和的结果作为新的候选值加入队列。 5. 重复步骤4直到遍历完所有元素。 6. 当队列的大小超过k时,将队列中的最小值弹出。 7. 最后,队列中的所有候选值之和即为前k小的组合之和。 以下是使用优先队列解决HDU4546问题的代码示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <functional> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); // 对数组a进行排序 priority_queue<long long, vector<long long>, greater<long long>> pq; // 最小堆 pq.push(0); // 初始情况,前0个数的组合之和为0 for (int i = 0; i < n; i++) { long long num = pq.top(); // 取出当前队列中的最小值 pq.pop(); for (int j = i + 1; j <= n; j++) { pq.push(num + a[i]); // 将所有加和结果作为新的候选值加入队列 num += a[i]; } if (pq.size() > k) { pq.pop(); // 当队列大小超过k时,弹出最小值 } } long long sum = 0; while (!pq.empty()) { sum += pq.top(); // 求队列中所有候选值之和 pq.pop(); } cout << sum << endl; return 0; } ``` 使用优先队列的方法可以有效地找到前k小的组合之和,时间复杂度为O(nklog(k))。希望这个解法对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值