2024年3月25號題解

lwj1239發表於2024-03-26

Eight

解題思路

  1. 因為終點狀態是固定的,而從終點到起點是可以走到的,那麼起點到終點也是可以走到的,因為它是一個無向圖
  2. 那麼我們可以把所有可以到達的狀態存起來,而到達不了的輸出不可能
  3. 那麼我們就可以一次初始化,就得到所以情況了

程式碼實現

#include <sstream>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_map>
#include<queue>
#define Maxn 362880+5//876543210的hash值為362880 即最多出現362880種可能

using namespace std;

static const int FAC[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };    // 階乘
//佇列中存放的資訊
struct p {
        char s[10];//表示當前圖的狀態
        int hash;//當前圖狀態的康拓值
        int index;//空格所在的位置
};
bool v[Maxn];//用來標記可以到達的狀態
string path[Maxn];//存放從終點到一種狀態的路徑
int result = 46234;//123456780,終點狀態的康拓值
p q[Maxn];//佇列
int l = 0;//佇列頭
int r = 0;//佇列尾
p s = { "123456780", result, 8 };//開始位置
p t;
int d[4][2] = {//四個方向
        {-1, 0}, {1, 0}, {0, -1}, {0, 1}
};

//康託展開
int cantor(char* a)
{
        int x = 0;
        for (int i = 0; i < 9; ++i)
        {
                int smaller = 0;  // 在當前位之後小於其的個數
                for (int j = i + 1; j < 9; ++j)
                {
                        if (a[j] < a[i])
                                smaller++;
                }
                x += FAC[9 - i - 1] * smaller; // 康託展開累加
        }
        return x + 1;  // 康託展開值
}

void bfs()
{
        v[s.hash] = true;//標記當前狀態可以到達
        path[s.hash] = "";//終點到當前狀態的路徑為NULL
        q[r++] = s;//放入佇列

        while (l < r) {//佇列不為空
                s = q[l++];//彈出佇列元素

                int x = s.index / 3;//計算在圖中的下標
                int y = s.index % 3;

                for (int i = 0; i < 4; i++) {//列舉四個方向
                        int nx = x + d[i][0];//要交換的數的位置
                        int ny = y + d[i][1];

                        if (nx >= 0 && ny >= 0 && nx < 3 && ny < 3) {//沒有越界
                                t = s;//複製一份方便操作

                                swap(t.s[nx * 3 + ny], t.s[t.index]);//模擬移動過程
                                int newHash = cantor(t.s);//計算改變之後的康拓值
                                if (!v[newHash]) {//如果沒有到達過這種狀態
                                        t.hash = newHash;//更新康拓值
                                        t.index = nx * 3 + ny;//更新空格的位置
                                        switch (i) {//判斷是哪一個操作
                                            case 0: {
                                                    path[t.hash] = path[s.hash] + "d";//因為是從終點到起點所以是反過來的操作
                                                    break;
                                            }
                                            case 1: {
                                                    path[t.hash] = path[s.hash] + "u";
                                                    break;
                                            }
                                            case 2: {
                                                    path[t.hash] = path[s.hash] + "r";
                                                    break;
                                            }
                                            case 3: {
                                                    path[t.hash] = path[s.hash] + "l";
                                                    break;
                                            }
                                        }
                                        q[r++] = t;//入隊
                                        v[newHash] = true;//標記這種狀態
                                }
                        }
                }
        }
}

int main() {
        bfs();

        string a;

        while (getline(cin, a)) {
                if (a.size() == 0) {
                        break;
                }

                char s[10] = "";
                int size = 0;

                for (int i = 0; i < a.size(); i++) {
                        if (a[i] != ' ') {
                                if (a[i] != 'x') {
                                        s[size++] = a[i];
                                }
                                else {
                                        s[size++] = '0';
                                }
                        }
                }

                int hash = cantor(s);//圖的狀態用康拓值來表示

                if (!v[hash]) {//為0代表不能到達
                        cout << "unsolvable" << endl;
                }
                else {
                        reverse(path[hash].begin(), path[hash].end());//因為是起點到終點所以需要翻轉,不然過不了
                        cout << path[hash] << endl;
                }
        }

        return 0;
}

勝利大逃亡(續)

解題思路

  1. 分層圖最短路演算法
  2. 不把圖中的節點當做bfs的節點,而把圖中的節點加上題目要求的狀態當做我們bfs的節點
  3. 下面就是bfs板子

程式碼實現

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <cstring>

using namespace std;

const int N = 21;

struct p {
        int x;
        int y;
        int status;
};

int n;
int m;
int t;
char map[N][N];
p s;
p q[N * N * N * N * N];
int sx;
int sy;
int d[4][2] = {
        {-1, 0}, {1, 0}, {0, -1}, {0, 1}
};
bool v[N][N][1 << 11 + 1] = { 0 };

void solve()
{
        memset(v, 0, sizeof(v));
        int level = 0;
        int l = 0;
        int r = 0;
        for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                        cin >> map[i][j];
                        if (map[i][j] == '@') {
                                sx = i;
                                sy = j;
                        }
                }
        }
        v[sx][sy][0] = 1;

        s.x = sx;
        s.y = sy;
        s.status = 0;

        q[r++] = s;

        while (l < r) {
                int size = r - l;

                if (level >= t) {
                        cout << -1 << endl;
                        return;
                }

                for (int i = 0; i < size; i++) {
                        s = q[l++];

                        if (map[s.x][s.y] == '^' && level < t) {
                                cout << level << endl;
                                return;
                        }

                        for (int j = 0; j < 4; j++) {
                                int nx = s.x + d[j][0];
                                int ny = s.y + d[j][1];
                                int ns = s.status;

                                if (nx < 0 || nx >= n || ny < 0 || ny >= m || map[nx][ny] == '*') {
                                        continue;
                                }

                                if (map[nx][ny] >= 'a' && map[nx][ny] <= 'j' && !v[nx][ny][ns]) {
                                        ns |= 1 << (map[nx][ny] - 'a');
                                        v[nx][ny][ns] = 1;
                                        q[r].x = nx;
                                        q[r].y = ny;
                                        q[r++].status = ns;

                                }
                                else if (map[nx][ny] >= 'A' && map[nx][ny] <= 'J') {
                                        if ((ns >> (map[nx][ny] - 'A') & 1) && !v[nx][ny][ns]) {
                                                v[nx][ny][ns] = 1;
                                                q[r].x = nx;
                                                q[r].y = ny;
                                                q[r++].status = ns;
                                        }
                                }
                                else {
                                        if (!v[nx][ny][ns]) {
                                                v[nx][ny][ns] = 1;
                                                q[r].x = nx;
                                                q[r].y = ny;
                                                q[r++].status = ns;
                                        }
                                }
                        }
                }
                level++;
        }

        cout << -1 << endl;
}

int main()
{
        while (~scanf("%d%d%d", &n, &m, &t)) {
                solve();
        }

        return 0;
}

相關文章