2024年3月25号题解

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;
}

 

posted @ 2024-03-26 00:25  lwj1239  阅读(16)  评论(0)    收藏  举报