拯救大兵瑞恩「bitset状态压缩 + BFS」

拯救大兵瑞恩

题目描述:

n * m的地图,有p类门,当然对应的就有p类钥匙可以开对应的门,拿到对应门的钥匙才能开对应的门,门是双开门,还有若干个不可逾越的墙,你现在在(1, 1),你要去到(n, m),问最短路程

思路:

一看这个题就很难写,本来是不想写的,后来静下心来看了看,感觉也不是特别难写,就顺手写了

我的整体思路是将二维地图压缩成一维,然后跑BFS,bfs的队列塞的是一个结构体,结构体里面有三个参数,当前点对应的一维的坐标、走过的距离、拿到的钥匙,前两个是int型,第三个是bitse,因为他可以下标访问还可以进行或操作

写了两个函数:将二维坐标转换成一维坐标的getid、将一维坐标转换成二维坐标getpii

用一个二维数组来处理输入的两个点之间的关系,初始化为-1,再根据输入的来修改,最后-1表示可以通行,0表示是墙不可通行,x表示是一个有门x,需要有钥匙x才能通行

对于输入的钥匙,因为每个位置可能有多个钥匙,所以我开了一个biset数组,将点的二维压成一维后存他的钥匙

BFS的时候,先初始化一号点,特别是要初始化一号点的初始钥匙,更新的时候先判断是否出界,再判断是否是墙,或者有没有能开门的钥匙,能到达对应点的时候就更新当前状态对应的钥匙,塞进队列

记得开一个二维的vis数组,第一维存压缩过的第一维,第二维存当前状态的钥匙,这里可以用bitset的一个转换成无符号整数的函数来搞

#include <bits/stdc++.h>
using namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define y1 y114514

typedef long long ll;
typedef pair <int,int> pii;

#define MAX 300000 + 50
int n, m, k, p;
int x1, x2, y1, y2, g;

int tr[150][150];
bitset<30>key[205];
bool vis[300][300];

int getid(int x, int y){
    return (x - 1) * m + y;
}

pii getpii(int p){
    return m_p((p + m - 1) / m, ((p - 1) % m) + 1);
}

int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};

struct ran{
    int u, d;
    bitset<30>fuck;
};

bool judge(int x, int y){
    if(x > n || x < 1 || y > m || y < 1)return false;
    return true;
}

void bfs(){
    queue<ran>q;
    bitset<30>f = 0;
    f |= key[1];
    q.push({1, 0, f});
    while (!q.empty()) {
        auto [u, d, fuck] = q.front();q.pop();
        if(vis[u][fuck.to_ulong()])continue;
        vis[u][fuck.to_ulong()] = 1;
        if(u == n * m){
            cout << d << endl;
            return;
        }
        auto [x, y] = getpii(u);
        for(int i = 0; i < 4; ++i){
            int xx = x + dx[i];
            int yy = y + dy[i];
            int p = tr[getid(x, y)][getid(xx, yy)];
            if(p == 0 || !judge(xx, yy))continue;
            if(p == -1 || (p != -1 && fuck[p])){
                bitset<30>fuckk = fuck;
                fuckk |= key[getid(xx, yy)];
                q.push({getid(xx, yy), d + 1, fuckk});
            }
        }
    }
    cout << -1 << endl;
}

void work(){
    cin >> n >> m >> p >> k;
    mem(tr, -1);
    while (k--) {
        cin >> x1 >> y1 >> x2 >> y2 >> g;
        tr[getid(x1, y1)][getid(x2, y2)] = g;
        tr[getid(x2, y2)][getid(x1, y1)] = g;
    }
    cin >> k;
    while (k--) {
        cin >> x1 >> y1 >> g;
        key[getid(x1, y1)][g] = 1;
    }
    bfs();
}


int main(){
    io;
    work();
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值