[网络流24题] 孤岛营救问题 (状压搜索 )

题目链接

好吧,说是网络流24题,但是我首先想到的是状压搜索

第一次写状压搜索,竟然一次过,挺惊讶的。

对于钥匙, 因为只有 10 把, 所以, 我们可以把一个时刻有多少把钥匙,用一个数来表示,比如 0 就表示此时身上一把钥匙都没有, 5 的二进制是 101 从低位开始, 表示他有钥匙 1 和 3
这样就可以开心的搜索了

//代码中 从低位开始, 第2表示 钥匙1    第3表示 钥匙2
#include <bits/stdc++.h>
const int maxn = 12;
using namespace std;
typedef long long ll;
int xiang[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
struct note
{
    int x, y, z;        //x y 坐标   z 拥有的钥匙状态
    int bu;         //步数
    note() {}
    note(int x1, int y1, int z1, int bu1)
    {
        x = x1, y = y1, z = z1, bu = bu1;
    }
} temp;
int suo[maxn][maxn][maxn][maxn]; //suo[i][j][k][l]  (i,j) --> (k, l) 有某类型的锁
int yao[maxn][maxn][maxn];       //yao[i][j][k]   (i,j) 有 yao[i][j][0]把钥匙 一个单元格有可能有多把钥匙
bool vis[maxn][maxn][(1 << 11)]; //标记  vis[i][j][x]  x 是 (i,j)的钥匙状态
int n, m, p, k;

void bfs()
{
    temp.x = temp.y = 1;
    temp.bu = temp.z = 0;
    for (int i = 1; i <= yao[1][1][0]; i++) //  初始位置(1,1)可能有钥匙
        temp.z = temp.z | (1 << yao[1][1][i]);
    // printf("%d\n", temp.z);
    vis[1][1][temp.z] = true;
    queue<note> q;
    q.push(temp);
    int ans = -1;
    while (!q.empty())
    {
        temp = q.front();
        q.pop();
        if (temp.x == n && temp.y == m)
        {
            ans = temp.bu;
            break;
        }
        for (int i = 0; i < 4; i++)
        {
            int tx = temp.x + xiang[i][0];
            int ty = temp.y + xiang[i][1];
            if (tx < 1 || ty < 1 || tx > n || ty > m || suo[temp.x][temp.y][tx][ty] == -1) //越界     本来就过不去
                continue;
            if (suo[temp.x][temp.y][tx][ty] != 0 && !(temp.z & (1 << suo[temp.x][temp.y][tx][ty]))) //有锁 没钥匙
                continue;
            if (vis[tx][ty][temp.z] == true)    //这个坐标,同样的钥匙状态已经去过了
                continue;
            vis[tx][ty][temp.z] = true;     //标记去过
            int tz = temp.z;
            for (int i = 1; i <= yao[tx][ty][0]; i++)
            {
                tz = tz | (1 << yao[tx][ty][i]);
            }
            vis[tx][ty][tz] = true;         //标记去过   将前后钥匙状态都标记,能减少搜索量
            q.push(note(tx, ty, tz, temp.bu + 1));
        }
    }
    printf("%d\n", ans);
}

int main()
{
    scanf("%d%d%d", &n, &m, &p);
    scanf("%d", &k);
    while (k--)
    {
        int x1, y1, x2, y2, g;
        scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &g);
        if (g == 0)
            g = -1;
        suo[x1][y1][x2][y2] = g;    // (x1, y1)  ---> (x2, y2) 的路上有一个 g 类型的锁  g = -1 表示不通
        suo[x2][y2][x1][y1] = g;
    }
    scanf("%d", &k);
    while (k--)
    {
        int x, y, q;
        scanf("%d%d%d", &x, &y, &q);
        yao[x][y][0]++;
        yao[x][y][yao[x][y][0]] = q;
    }
    bfs();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值