题目: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;
}