• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • YouClaw
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

yongchaoD

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

胜利大逃亡+HDU 1885 Key Task (bfs迷宫状压,钥匙开门问题)

题意:这两个题都是一类问题,迷宫中一些点是门,必须要有对应的钥匙才能开门,才能走,迷宫中的每个点都是能重复走的,问到达终点的最短步数。

思路:有2个问题:1:如何表示某种钥匙的状态(拿或没拿) 2:一个点如何重复走?常规的是vis数组,不能重复走。
1:这就是这类题的巧妙之处了,状压。钥匙的种类肯定是有上限的,题1的钥匙种类最多10把,用10位二进制表示,0代表没拿,1代表拿了。10位也就是2的10次方(最大也就1024)。开一个结
构体,中有key变量,表示该点的钥匙状态。
2:一个点重复走,是拿了钥匙,然后走重复路开门的情况,那vis数组就要开到3维了,vis[][][这一个维度表示钥匙状态的访问],当拿了一把钥匙,vis是会被重新刷新的,这样就能重复走。

代码细节:1:状压其中涉及到的位运算,很基础,看不懂了多看下就懂了
2:!!!!!这两道题最要注意到的细节来了,第二题MLE了很多次,还是c哥给我讲明白了。第一题和第二题的钥匙符号表示是不一样的,一题钥匙是从'a'往后连续表示,而二题不是,虽然钥匙种类还少,但是有'g'。位运算中直接mp[i][j]-'a'是存在大于10的,这样10位二进制1024就不够,vis[][][1024]还会越界,所以要对钥匙符号预处理下,用map的键值存符号,然后实值还是从0开始存。

胜利大逃亡题解:

点击查看代码
//状态压缩,用一个数字来表示多个变量状态,
#include<bits/stdc++.h>
using namespace std;
int n,m,t,st_x,st_y;
char mp[25][25];
int vis[25][25][1025];
int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

struct Nod{
    int x,y,step,key;
}temp,p;

int bfs(int sx,int sy){
    queue<Nod>q;
    q.push({sx,sy,0,0});
    while(!q.empty()){
        temp=q.front();
        q.pop();

        for (int i = 0; i < 4; i++) {
            p.x = temp.x + dir[i][0], p.y = temp.y + dir[i][1], p.step = temp.step + 1, p.key = temp.key;

            if (p.x >= 0 && p.x < n && p.y >= 0 && p.y < m && !vis[p.x][p.y][p.key] && mp[p.x][p.y] != '*') {
                if (mp[p.x][p.y] == '^' && p.step<t) return p.step;//终点
                else if (mp[p.x][p.y] >= 'a' && mp[p.x][p.y] <= 'z') {//钥匙
                    int stc = mp[p.x][p.y] - 'a';
                    if ((p.key & (1 << stc)) == 0) { p.key=p.key | (1 << stc); }//没有这把钥匙
                }
                else if (mp[p.x][p.y] >= 'A' && mp[p.x][p.y] <= 'Z') {//门
                    int stc = mp[p.x][p.y] - 'A';
                    if (!(p.key & (1 << stc))) { continue; }//没钥匙
                }
                q.push(p);
                vis[p.x][p.y][p.key] = 1;
            }
        }
    }
    return -1;
}

int main()
{
    while(~scanf("%d%d%d",&n,&m,&t)){
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++){
            getchar();
            for(int j=0;j<m;j++){
                scanf("%c",&mp[i][j]);
                if(mp[i][j]=='@') st_x=i,st_y=j;
            }
        }

        int re=bfs(st_x,st_y);
        printf("%d\n",re);
    }
    return 0;
}

HDU 1885 Key Task题解:(最佳优化)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 105;
char ch[MAXN][MAXN];
int stp[MAXN][MAXN][20];
int sx, sy; // 起始位置
int hx[4] = {0, 1, 0, -1};
int hy[4] = {1, 0, -1, 0};
struct State {
    int x, y, st;
};
map<char,int>mp;
queue<State> q;
int bfs(int n, int m) {
    memset(stp, -1, sizeof stp);
    State sta, to;
    sta.x = sx;
    sta.y = sy;
    sta.st = 0;
    q.push(sta);
    stp[sta.x][sta.y][sta.st] = 0;

    while (!q.empty()) {
        to = q.front();
        q.pop();

        for (int i = 0; i < 4; i++) {
            sta.x = to.x + hx[i];
            sta.y = to.y + hy[i];
            sta.st = to.st;

            if (ch[sta.x][sta.y] == '#') continue;
            if (sta.x < 0 || sta.y < 0 || sta.x >= n || sta.y >= m) continue;

            if (ch[sta.x][sta.y] >= 'a' && ch[sta.x][sta.y] <= 'y') {//这里相对题解1更优化了,用了 | 运算,0|1=1,1|1=1,0|0=1 (0是没钥匙,1是拿到了钥匙,0|1=1)
                sta.st |= (1 << mp[ch[sta.x][sta.y]]); // 拿钥匙
            }
            if ((ch[sta.x][sta.y] >= 'a' && ch[sta.x][sta.y] <= 'y') ||ch[sta.x][sta.y] == '.' ||(ch[sta.x][sta.y] >= 'A' && ch[sta.x][sta.y] <= 'Y' && (sta.st & (1 << (mp[ch[sta.x][sta.y]]))) != 0))
            {
                if (stp[sta.x][sta.y][sta.st] == -1) {
                    stp[sta.x][sta.y][sta.st] = stp[to.x][to.y][to.st] + 1;
                    q.push(sta);
                }
            }
            if (ch[sta.x][sta.y] == 'X') {
                return stp[to.x][to.y][to.st] + 1;
            }
        }
    }
    return -1;
}

int main() {
    int n, m;
    mp['b']=0;
    mp['B']=0;
    mp['y']=1;
    mp['Y']=1;
    mp['r']=2;
    mp['R']=2;
    mp['g']=3;
    mp['G']=3;
    while (cin>>n>>m) {
        if(n==0||m==0)break;
        while (!q.empty()) q.pop();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                cin >> ch[i][j];
                if (ch[i][j] == '*') {
                    sx = i;
                    sy = j;
                    ch[i][j] = '.';
                }
            }
        }
        int result = bfs(n, m);
        if(result==-1)printf("The poor student is trapped!\n");
        else printf("Escape possible in %d steps.\n",result);
    }
    return 0;
}

posted on 2024-07-10 11:49  yongchaoD  阅读(49)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3