2024年3月28号题解

Key Task

解题思路

  1.  分层图最短路算法
  2. 把图中的节点和状态当作一个节点而不是原图中的点和胜利大逃亡(续)是一个模型,然后因为是求最短路所以使用bfs算法来解决

代码实现

#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 N = 101;//最多100个点

struct p {//队列中存放的状态,即真正遍历的点,需要再加一个状态
        int x;//行坐标
        int y;//列坐标
        int status;//得到了几把钥匙,二进制位上的1表示有对应的钥匙,0代表没有对应的钥匙
};

int h, c;//有几行几列
char s[N][N];//用来存放原始的图
int sx;//起点的行坐标
int sy;//起点的列坐标
bool v[N][N][(1 << 4) + 1];//标记有那些状态访问过
//N * N是原始图的状态但还有钥匙的状态一共有4把钥匙所以最多有2^4中可能,那么到每个位置就是N * N * 2 ^ 4中可能
p q[N * N * ((1 << 4) + 1)];//队列中最多容纳这些状态
int d[4][2] = {//上下左右走
        {-1, 0}, {1, 0}, {0, -1}, {0, 1}
};
int step[256];//存放钥匙对应的在变量(status)中的二进制位数

void solve() {
        memset(v, 0, sizeof(v));//把v数组全部赋值为0
        for (int i = 0; i < h; i++) {//读取h行
                sc("%s", s[i]);
                //找到起点的位置
                for (int j = 0; j < c; j++) {
                        if (s[i][j] == '*') {
                                sx = i;
                                sy = j;
                                break;
                        }
                }
        }
        //队列头和队列尾初始化为0代表没有队列中没有元素
        int l = 0;
        int r = 0;
        p start = { sx, sy, 0 };//起点的状态刚开始没有钥匙,所以status赋值为0
        int level = 0;//第几层,层数就是我们走的路径即秒数

        v[sx][sy][0] = 1;//起点状态标记为1表示走过
        q[r++] = start;//起点状态入队进行bfs

        while (l < r) {//只要队列中还有元素
                int size = r - l;//取出当前层数的节点个数,进行层序遍历

                for (int i = 0; i < size; i++) {//取出当前层的每一个节点
                        start = q[l++];//出队

                        if (s[start.x][start.y] == 'X') {//如果到达终点了
                                pr("Escape possible in %d steps.\n", level);//打印需要的时间
                                return;//直接结束bfs因为第一次就是最短路径
                        }

                        for (int i = 0; i < 4; i++) {//遍历四个方向
                                //新的坐标
                                int nx = start.x + d[i][0];
                                int ny = start.y + d[i][1];
                                //如果没有越界并且这个状态没有被访问过并且还不是墙
                                if (nx >= 0 && nx < h && ny >= 0 && ny < c && !v[nx][ny][start.status] && s[nx][ny] != '#') {
                                        p t = start;//因为不能改变start,所以用一个临时变量存起来
                                        if (s[nx][ny] == 'b' || s[nx][ny] == 'y' || s[nx][ny] == 'r' || s[nx][ny] == 'g') {//如果是一把钥匙
                                                //更新一下状态
                                                t.x = nx;
                                                t.y = ny;
                                                t.status |= 1 << step[s[nx][ny]];//放入对应的位置
                                                v[nx][ny][t.status] = 1;//把状态标记为访问过
                                                q[r++] = t;//入队
                                        }
                                        else if ((s[nx][ny] == 'B' || s[nx][ny] == 'Y' || s[nx][ny] == 'R' || s[nx][ny] == 'G')) {//碰到门了
                                                if (((t.status >> step[s[nx][ny]]) & 1)) {//如果有对应的钥匙那么就可以走,把这个if写在上面
                                                    //因为没有对应的钥匙就不能走那么它就执行else了就入队了,就不对了
                                                        //更新可以走的状态
                                                        t.x = nx;
                                                        t.y = ny;
                                                        v[nx][ny][t.status] = 1;
                                                        q[r++] = t;//入队
                                                }       
                                        }
                                        else {//如果不是钥匙也不是门,那么只有一种可能就是空地,那么直接入队
                                                t.x = nx;
                                                t.y = ny;
                                                t.status = start.status;
                                                v[nx][ny][t.status] = 1;
                                                q[r++] = t;
                                        }
                                }
                        }
                }
                level++;//层序遍历,所以结束的时候层数加一
        }
        pr("The poor student is trapped!\n");//队列为空还没有搜索到出口代表出不去所以打印出不去
}

int main() {
        step['B'] = 0;//b钥匙在最低位
        step['Y'] = 1;//y钥匙在第一位
        step['R'] = 2;//r钥匙在第二位
        step['G'] = 3;//g钥匙在第三位
        step['b'] = 0;//b钥匙在最低位
        step['y'] = 1;//y钥匙在第一位
        step['r'] = 2;//r钥匙在第二位
        step['g'] = 3;//g钥匙在第三位
        while (~sc("%d%d", &h, &c), h + c) {//读取行和列,如果h+c的值为0,代表h和c的值都为0
                solve();
        }

        return 0;
} 

Beat

解题思路

  1. dfs把所有的可能都搜索出来,那么只要维护一个变量就可以了,然后打印最大值
  2. dfs枚举所有的问题,看满不满足难度是递增的,如果满足继续递归调用

代码实现

#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 N = 16;//最多16种问题

int n;//问题的个数
int a[N][N];//第ij位置表示解决第i个问题后解决第j问题需要的时间
bool v[N];//用来标记解决过的问题
int ans;//最多可以解决多少个问题

void dfs(int pre, int m, int cnt)//pre表示上一个解决的问题,m表示上一个解决的问题的难度,cnt表示解决问题的个数
{
        if (cnt > ans) {//每次都更新答案
                ans = cnt;
        }
        for (int i = 2; i <= n; i++) {//遍历所有的问题,因为第一个问题是第一次就解决的所以从第二个问题开始
                if (!v[i] && a[pre][i] >= m) {//如果这个问题没有被解决,并且满足难度越来越高的条件
                        v[i] = 1;//标记已经解决
                        dfs(i, a[pre][i], cnt + 1);//解决了i问题所以是i,而难度是a[pre][i],解决问题的个数要加一
                        v[i] = 0;//恢复现场
                }
        }
}

int main() {
        while (~sc("%d", &n))
        {
                ans = 0;
                for (int i = 1; i <= n; i++) {
                        for (int j = 1; j <= n; j++) {
                                sc("%d", a[i] + j);
                        }
                }
                memset(v, 0, sizeof(v));
                v[1] = 1;
                ans = 1;
                dfs(1, 0, 1);

                pr("%d\n", ans);
        }

        return 0;
}

 

posted @ 2024-03-29 00:37  lwj1239  阅读(24)  评论(0)    收藏  举报