hdu 6111 迷宫出逃(状态压缩)

题目:hdu6111

分析:
由于m*n只有64,所以想到状态压缩,其中一个状态rev的第((i-1)*m + j-1)表示(i, j)位置是否反转过,还有一个状态key表示该位置是否已经拿到钥匙
难点在于bfs判重,理论上状态至少有2^64个,但是实际上真正有用的状态却不是很多,用一个vector数组+hash来存储这些状态即可不超内存。
每次判断是否为出口且是否有钥匙,若有则退出。
ps:由于在写的时候误将(unsigned long long)1 << ((x-1)*m + j-1)写成了(unsigned long long)(1 << ((x-1)*m + j-1)), 惨案。。
pss:感觉存在这样一组数据,首先它是不可解的,但是由于构造特殊,会出现循环,所以不断有新的状态加进来而导致程序不会结束,oj评测没有这样的数据,所以如果存在这样的数据的话直接在bfs里面加一个最大循环限制即可

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

typedef unsigned long long LL;
using namespace std;

const int maxn = 65 + 5;
const int maxm = 65 + 5;
const LL mod = (LL)1e4;

char maze[maxn][maxm];
int n, m, ans;
int sx, sy, ex, ey, kx, ky;

struct State{
    LL rev;
    LL key;
    int cnt;
    int x, y;   
};

struct HashState{
    LL rev, key;
    int x, y;
    LL count() {
    return (rev % mod + key + x + y) % mod;
    }
    bool operator == (const HashState &a) const {
    return x == a.x && y == a.y && rev == a.rev && a.key == key;
    }
};

vector <HashState> has[mod + 5];
queue <State> Q;

void add(LL rev, LL key, int cnt, int x, int y) {
    HashState hs = {rev, key, x, y};
    LL ct = hs.count();
    for (int i = 0; i < has[ct].size(); i ++)
    if (has[ct][i] == hs)
        return;
    has[ct].push_back(hs);
    State st = {rev, key, cnt, x, y};
    Q.push(st);
}

LL reverse(int x, int y, LL rev) {
    if (x-1 >= 1) rev ^= ((LL)1 << ((x-2)*m + y-1));
    if (y + 1 <= m) rev ^= ((LL)1 << ((x - 1) * m + y));
    if (x + 1 <= n) rev ^= ((LL)1 << (x*m + y - 1));
    if (y - 1 >= 1) rev ^= ((LL)1 << ((x - 1) * m + y - 2));
    return rev;
}

void update(State cur, int nx, int ny){
    if (nx < 1 || nx > n || ny < 1 || ny > m) return;
    LL tmp = ((LL)1 << ((nx-1)*m + ny - 1)) & cur.rev;
    if (tmp != 0 && maze[nx][ny] == 'x')
    add(cur.rev, cur.key, cur.cnt+1, nx, ny);

    else if (tmp == 0 && maze[nx][ny] != 'x') {
    if (nx == kx && ny == ky)
        add(cur.rev, 1, cur.cnt + 1, nx, ny);
    else if (maze[nx][ny] == '*')
        add(reverse(nx, ny, cur.rev), cur.key, cur.cnt + 1, nx, ny);
    else add(cur.rev, cur.key, cur.cnt+1, nx, ny);
    }
}

void solve(){
    while (!Q.empty()) Q.pop();
    State st = {0, 0, 0, sx, sy};
    Q.push(st);
    for (int i = 0; i < mod; i ++) has[i].clear();

    while (!Q.empty()) {
    State sta = Q.front(); Q.pop();
    if (sta.x == ex && sta.y == ey && sta.key == 1) {
        ans = sta.cnt;
        return;
    }
    update(sta, sta.x - 1, sta.y);
    update(sta, sta.x, sta.y + 1);
    update(sta, sta.x+1, sta.y);
    update(sta, sta.x, sta.y - 1);
    }
}

int main(){
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);

    int tot; scanf("%d", &tot);
    for (int kase = 1; kase <= tot; kase ++) {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i ++) scanf("%s", maze[i] + 1);

    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
        if (maze[i][j] == 'S') {
            sx = i; sy = j; maze[i][j] = '.';
        }
        else if (maze[i][j] == 'E') {
            ex = i; ey = j; maze[i][j] = '.';
        }
        else if (maze[i][j] == 'K') {
            kx = i; ky = j; maze[i][j] = '.';
        }
    ans = -1;
    solve();
    if (kase != 1) printf("\n");
    printf("Case #%d:\n%d\n", kase, ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值