『題解』孤島營救問題

題目連接

LuoGu P4011 孤島營救問題node

LOJ #6121. 「網絡流 24 題」孤島營救問題ios

題目簡述

一個 \(n \times m\) 的矩陣,每一個單元位置用一個有序數對(行號,列號)表示。數組

上下左右四個方向相鄰的兩個單元格之間存在一下狀況:網絡

  • 直接相連函數

  • 符合某種條件的狀況下相連測試

  • 不相連優化

其中某種條件分爲 \(p\) 類要素,使一種條件成立的要素相同,不一樣條件成立的要素不一樣。spa

初始位置爲 \((1,1)\) ,問如何以最少步數到達 \((n,m)\)debug

解題思路

數據範圍這麼友好,不暴力怎麼對得起出題人呢??/jkcode

考慮定義

  • 一個四維數組表示 \((x_1,y_1) \to (x_2,y_2)\) 是否符合條件相連通。

  • \(vis[i][j][k]\) 表示條件要素爲 \(k\) 的狀況下,\((i,j)\) 位置是否已經查找過。

  • \(key[i][j]\) 表示第 \(key\) 類要素須要在 \((i,j)\) 單元獲取。

這裏用用到狀態壓縮存儲條件要素。(不會狀壓的請去睡覺)

而後,而後就能夠直接枚舉 \(DFS\) 了。(不會 \(DFS\) 搜最短路徑的請去睡覺)

小小優化

定義結構體記錄單元(行號,列號,知足的條件,到該單元的最小花費),用隊列存儲(將路徑記錄下來),減小枚舉數量。

友情提示

  • 鑰匙質量不錯,不是一次性的woc

  • 鑰匙作工不錯,一個單元能夠放多把鑰匙woc

  • 初始點好像並無說不能放鑰匙woc

  • 輸出 \(-1\) 贊~

  • \(DFS\) 不加 return 能夠卡掉五個測試點。。。(而後 \(debug\) 了一下午)

CODE

/*

Name: #6121. 「網絡流 24 題」孤島營救問題
Solution: 最短路
   
By Frather_

*/
#include <iostream>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
// #include <map>
#include <stack>
#define ll long long
#define InF 0x7fffffff
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
#define kMod2 19260817
#define kMod3 19660813
#define base 1331
using namespace std;
/*=========================================快讀*/
int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
/*=====================================定義變量*/
int n, m, p;
int k;
int s;
int map[20][20][20][20], key[20][20];
struct node
{
    int x, y;
    int key;
    int dis;
};
bool vis[20][20][1 << 11];
queue<node> q;

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

int ans = -1;
/*===================================自定義函數*/
void bfs()
{
    q.push((node){1, 1, 0 | key[0][0], 0}); //初始化第一個位置
    vis[1][1][0 | key[1][1]] = true;
    while (!q.empty())
    {
        node now = q.front(), next;
        q.pop();
        for (int i = 1; i <= 4; i++)
        {
            next.x = now.x + dx[i];
            next.y = now.y + dy[i];
            if (next.x < 1 || next.x > n || next.y < 1 || next.y > m || !map[now.x][now.y][next.x][next.y]) //若dfs越界或者該兩單元間不存在可通路(即有「一堵不可逾越的牆」),跳過
                continue;
            if ((map[now.x][now.y][next.x][next.y] == -1) || (now.key & map[now.x][now.y][next.x][next.y]))
            {
                if (!key[next.x][next.y])
                    next.key = now.key;
                else
                    next.key = now.key | key[next.x][next.y];
                if (vis[next.x][next.y][next.key])
                    continue;
                vis[next.x][next.y][next.key] = true;
                next.dis = now.dis + 1;
                q.push(next);
                if (next.x == n && next.y == m)
                {
                    ans = next.dis;
                    return;
                }
            }
        }
    }
}
/*=======================================主函數*/
int main()
{
    n = read();
    m = read();
    p = read();
    k = read();
    memset(map, -1, sizeof(map));
    for (int i = 1; i <= k; i++)
    {
        int x_1 = read();
        int y_1 = read();
        int x_2 = read();
        int y_2 = read();
        int g = read();
        map[x_1][y_1][x_2][y_2] = g ? 1 << g - 1 : g;
        map[x_2][y_2][x_1][y_1] = map[x_1][y_1][x_2][y_2];
    }
    s = read();
    for (int i = 1; i <= s; i++)
    {
        int x = read();
        int y = read();
        int g = read();
        key[x][y] |= 1 << g - 1;
    }
    bfs();
    printf("%d\n", ans);
    return 0;
}

最後

感謝閱讀,留個點贊謝謝~

相關文章
相關標籤/搜索