2024年3月27號題解

lwj1239發表於2024-03-27

Open the Lock

解題思路

  1. 很明顯從起點到終點的距離等於終點到起點的距離,那麼它就是一個無向圖
  2. 那麼我們可以使用dbfs來進行剪枝,來最佳化我們的搜尋

程式碼實現

#define  _CRT_SECURE_NO_WARNINGS
#include <sstream>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_map>
#include<queue>
#include <set>
#define sc scanf
#define pr printf

using namespace std;

const int M = 10000;//最多10000種狀態

int t;//樣例個數
int q1[M];//從起點遍歷的佇列
int q2[M];//從終點遍歷的佇列
int l1;//q1的佇列頭
int l2;//q2的佇列頭
int r1;//q1的佇列尾
int r2;//q2的佇列尾
bool v1[M];//起點出發訪問過的狀態
bool v2[M];//從終點出發訪問過的狀態
int a[4];//用來存放狀態
int b[4];//暫時存放狀態

int getStatus(int a[]) {//給定一個陣列返回它對應的狀態
        int ans = a[0] * 1000 + a[1] * 100 + a[2] * 10 + a[3];

        return ans;
} 

void dbfs()//雙向bfs
{
        int s1 = 0;//起點狀態
        int s2 = 0;//終點狀態
        int level1 = 0;//從起點出發的層數
        int level2 = 0;//從終點出發的層數

        memset(v1, 0, sizeof(v1));//給v1陣列清0
        memset(v2, 0, sizeof(v2));//給v2陣列清0
        r2 = r1 = l2 = l1 = 0;

        sc("%d", &s1);//讀入起點的狀態
        sc("%d", &s2);//讀入終點的狀態

        v1[s1] = 1;//標記起點狀態已訪問
        v2[s2] = 1;//標記終點狀態已訪問
        q1[r1++] = s1;//把起點加入起點佇列
        q2[r2++] = s2;//把終點加入終點佇列
                
        while (l1 < r1 && l2 < r2) {//只要兩個佇列沒有空
                int size1 = r1 - l1;//計算起點佇列中的元素個數
                int size2 = r2 - l2;//計算終點佇列種的元素個數

                if (size1 <= size2) {//如果起點佇列中的元素個數更少
                        for (int i = 0; i < size1; i++) {//遍歷起點佇列
                                s1 = q1[l1++];//出隊
                                       
                                if (v2[s1]) {//如果在終點佇列中訪問過的狀態出現過,代表這條路徑可以從終點到起點
                                        pr("%d\n", level1 + level2);
                                        return;//第一次就是最短路徑
                                }

                                //取出對應的狀態
                                b[0] = a[0] = s1 / 1000;
                                b[1] = a[1] = s1 / 100 % 10;
                                b[2] = a[2] = s1 / 10 % 10;
                                b[3] = a[3] = s1 % 10;
                                //+1
                                for (int j = 0; j < 4; j++) {
                                        if (b[j] == 9) {
                                                b[j] = 1;
                                                int t = getStatus(b);
                                                if (!v1[t]) {
                                                        v1[t] = 1;
                                                        q1[r1++] = t;
                                                }
                                                b[j] = a[j];
                                        }
                                        else {
                                                b[j] += 1;
                                                int t = getStatus(b);
                                                if (!v1[t]) {
                                                        v1[t] = 1;
                                                        q1[r1++] = t;
                                                }
                                                b[j] = a[j];
                                        }
                                }

                                // -1
                                for (int j = 0; j < 4; j++) {
                                        if (b[j] == 1) {
                                                b[j] = 9;
                                                int t = getStatus(b);
                                                if (!v1[t]) {
                                                        v1[t] = 1;
                                                        q1[r1++] = t;
                                                }
                                                b[j] = a[j];
                                        }
                                        else {
                                                b[j] -= 1;
                                                int t = getStatus(b);
                                                if (!v1[t]) {
                                                        v1[t] = 1;
                                                        q1[r1++] = t;
                                                }
                                                b[j] = a[j];
                                        }
                                }
                                //swap
                                for (int j = 0; j < 3; j++) {
                                        swap(b[j], b[j + 1]);
                                        int t = getStatus(b);

                                        if (!v1[t]) {
                                                v1[t] = 1;
                                                q1[r1++] = t;
                                        }
                                        swap(b[j], b[j + 1]);
                                }
                        }
                        level1++;//層數加一
                }
                else {
                        for (int i = 0; i < size2; i++) {//遍歷終點佇列
                                s1 = q2[l2++];//出隊

                                if (v1[s1]) {//如果終點訪問過的狀態起點訪問過了,那麼這條路就是最短路滿足要求
                                        pr("%d\n", level1 + level2);
                                        return;
                                }
                                //取出對應的狀態
                                b[0] = a[0] = s1 / 1000;
                                b[1] = a[1] = s1 / 100 % 10;
                                b[2] = a[2] = s1 / 10 % 10;
                                b[3] = a[3] = s1 % 10;
                                //+1
                                for (int j = 0; j < 4; j++) {
                                        if (b[j] == 9) {
                                                b[j] = 1;
                                                int t = getStatus(b);
                                                if (!v2[t]) {
                                                        v2[t] = 1;
                                                        q2[r2++] = t;
                                                }
                                                b[j] = a[j];
                                        }
                                        else {
                                                b[j] += 1;
                                                int t = getStatus(b);
                                                if (!v2[t]) {
                                                        v2[t] = 1;
                                                        q2[r2++] = t;
                                                }
                                                b[j] = a[j];
                                        }
                                }

                                // -1
                                for (int j = 0; j < 4; j++) {
                                        if (b[j] == 1) {
                                                b[j] = 9;
                                                int t = getStatus(b);
                                                if (!v2[t]) {
                                                        v2[t] = 1;
                                                        q2[r2++] = t;
                                                }
                                                b[j] = a[j];
                                        }
                                        else {
                                                b[j] -= 1;
                                                int t = getStatus(b);
                                                if (!v2[t]) {
                                                        v2[t] = 1;
                                                        q2[r2++] = t;
                                                }
                                                b[j] = a[j];
                                        }
                                }
                                //swap相鄰元素
                                for (int j = 0; j < 3; j++) {
                                        swap(b[j], b[j + 1]);//交換
                                        int t = getStatus(b);

                                        if (!v2[t]) {
                                                v2[t] = 1;
                                                q2[r2++] = t;
                                        }
                                        swap(b[j], b[j + 1]);//再交換回來,就恢復原裝了
                                }
                        }
                        level2++;//層數加一
                }
        }
}

int main() {
        sc("%d", &t);

        while (t--) {
                dbfs();
        }

        return 0;
}