您的位置:首页 > 其它

【POJ】3523 The Morning after Halloween

2016-03-23 23:18 417 查看
1. 题目描述
$m \times n$的迷宫(最大为$16 \times 16$)包含最多3个点,这些点可以同时向相邻方向移动或保持停止,使用小写字母表示起始位置,使用大写字母表示中止位置。求最少经过多少时间,这些点可以从起始位置移动到对应的终止位置。

2. 基本思路
这是很经典的路径搜索问题,一般采用BFS。因为题目说每个$2 \times 2$个子矩阵,都至少有一个点为#,那么起始空白可走的点一定很少,因此,可以预处理这些点可以通过1个时间单位到达的有效位置。这样可以降低$5^3$的总排列。显然,同时对三个点组成的三元组进行状态压缩,这里采用移位。这些做完了,普通的BFS+map就已经可以解出正确解了。但是太慢了。因此,使用双向BFS+map,发现还是超时,原因是map太慢了(而且会随着状态的增加越来越慢)。那么,直接用数组存(注意不要MLE)。直接过了。双向BFS明显地提高了性能。

3. 代码

/* 3523 */
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <deque>
#include <bitset>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <climits>
#include <cctype>
#include <cassert>
#include <functional>
#include <iterator>
#include <iomanip>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,1024000")

#define sti                set<int>
#define stpii            set<pair<int, int> >
#define mpii            map<int,int>
#define vi                vector<int>
#define pii                pair<int,int>
#define vpii            vector<pair<int,int> >
#define rep(i, a, n)     for (int i=a;i<n;++i)
#define per(i, a, n)     for (int i=n-1;i>=a;--i)
#define clr                clear
#define pb                 push_back
#define mp                 make_pair
#define fir                first
#define sec                second
#define all(x)             (x).begin(),(x).end()
#define SZ(x)             ((int)(x).size())
#define lson            l, mid, rt<<1
#define rson            mid+1, r, rt<<1|1
#define INF                0x3f3f3f3f
#define mset(a, val)    memset(a, (val), sizeof(a))

const int maxn = 20;
const int maxm = 150;
int ID[maxn][maxn];
int sz[maxm];
int Move[maxm][5];
int visit[2][maxm][maxm][maxm];
char s[maxn][maxn];
map<char,int> ptb;
queue<int> Q[2];
int dir[5][2] = {
-1, 0, 1, 0, 0, -1, 0, 1, 0,0
};
int n, m, gn;
int st, ed;

inline bool judge(int x, int y) {
return x<0 || x>=n || y<0 || y>=m || s[x][y]=='#';
}

void init() {
int cnt = 0;
map<char,int>::iterator iter;

ptb.clr();

rep(i, 0, n) {
rep(j, 0, m) {
if (s[i][j] == '#')
continue;

ID[i][j] = cnt++;
if (s[i][j] != ' ')
ptb[s[i][j]] = ID[i][j];
}
}

rep(i, 0, n) {
rep(j, 0, m) {
if (s[i][j] == '#')
continue;

const int& id = ID[i][j];
sz[id] = 1;
Move[id][0] = id;
rep(k, 0, 4) {
int x = i + dir[k][0];
int y = j + dir[k][1];
if (judge(x, y))
continue;

Move[id][sz[id]++] = ID[x][y];
}
}
}

st = ed = 0;

for (char ch='a'; ch<='z'; ++ch) {
iter = ptb.find(ch);
if (iter != ptb.end()) {
st = (st << 8) | iter->sec;
iter = ptb.find(ch-'a'+'A');
#ifndef ONLINE_JUDGE
assert(iter != ptb.end());
#endif
ed = (ed << 8) | iter->sec;
}
}
}

int bfs1(const int qid) {
int cst, nst;
int qsz = SZ(Q[qid]);

while (qsz--) {
cst = Q[qid].front();
Q[qid].pop();

int step = visit[qid][0][0][cst] + 1;
rep(i, 0, sz[cst]) {
nst = Move[cst][i];
if (visit[qid][0][0][nst] == -1) {
if (visit[qid^1][0][0][nst] >= 0)
return step + visit[qid^1][0][0][nst];
visit[qid][0][0][nst] = step;
Q[qid].push(nst);
}
}
}

return -1;
}

int bfs2(const int qid) {
int cst[2], nst[2], tmp;
int qsz = SZ(Q[qid]);

while (qsz--) {
st = Q[qid].front();
Q[qid].pop();

per(i, 0, 2) {
cst[i] = st & 0xff;
st >>= 8;
}

int step = visit[qid][0][cst[0]][cst[1]] + 1;

rep(i, 0, sz[cst[0]]) {
nst[0] = Move[cst[0]][i];
rep(j, 0, sz[cst[1]]) {
nst[1] = Move[cst[1]][j];
if (nst[0]==nst[1] || (nst[0]==cst[1]&&nst[1]==cst[0]))
continue;

tmp = nst[0]<<8 | nst[1];
if (visit[qid][0][nst[0]][nst[1]] == -1) {
if (visit[qid^1][0][nst[0]][nst[1]] != -1)
return step + visit[qid^1][0][nst[0]][nst[1]];
visit[qid][0][nst[0]][nst[1]] = step;
Q[qid].push(tmp);
}
}
}
}

return -1;
}

inline bool check(int *nst, int *cst) {
return (nst[0]==cst[1] && nst[1]==cst[0]) || (nst[0]==cst[2] && nst[2]==cst[0]) || (nst[1]==cst[2] && nst[2]==cst[1]);
}

int bfs3(const int qid) {
int cst[3], nst[3], tmp;
int qsz = SZ(Q[qid]);

while (qsz--) {
st = Q[qid].front();
Q[qid].pop();

per(i, 0, 3) {
cst[i] = st & 0xff;
st >>= 8;
}

int step = visit[qid][cst[0]][cst[1]][cst[2]] + 1;

rep(i, 0, sz[cst[0]]) {
nst[0] = Move[cst[0]][i];
rep(j, 0, sz[cst[1]]) {
nst[1] = Move[cst[1]][j];
rep(k, 0, sz[cst[2]]) {
nst[2] = Move[cst[2]][k];
if (nst[0]==nst[1] || nst[1]==nst[2] || nst[0]==nst[2] || check(cst, nst))
continue;

tmp = (nst[0]<<16) | (nst[1]<<8) | (nst[2]);

if (visit[qid][nst[0]][nst[1]][nst[2]] == -1) {
if (visit[qid^1][nst[0]][nst[1]][nst[2]] != -1)
return step + visit[qid^1][nst[0]][nst[1]][nst[2]];
visit[qid][nst[0]][nst[1]][nst[2]] = step;
Q[qid].push(tmp);
}
}
}
}
}

return -1;
}

#define bibfs(n)\
int bibfs##n() {\
int tmp;    \
\
while (!Q[0].empty() || !Q[1].empty()) {\
tmp = bfs##n(0);\
if (tmp >= 0)    return tmp;\
tmp = bfs##n(1);\
if (tmp >= 0)    return tmp;\
}\
\
return -1;\
}

#define callbibfs(n) bibfs##n()

bibfs(1)
bibfs(2)
bibfs(3)

void solve() {
init();
int ans;

memset(visit, -1, sizeof(visit));
rep(i, 0, 2)
while (!Q[i].empty()) Q[i].pop();
visit[0][st>>16][(st>>8)&0xff][st&0xff] = 0;
visit[1][ed>>16][(ed>>8)&0xff][ed&0xff] = 0;
Q[0].push(st);
Q[1].push(ed);

if (gn == 1) {
ans = callbibfs(1);
} else if (gn == 2) {
ans = callbibfs(2);
} else {
ans = callbibfs(3);
}

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

int main() {
ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif

while (scanf("%d%d%d%*c",&m,&n,&gn)!=EOF && (n||m||gn)) {
rep(i, 0, n)
gets(s[i]);
solve();
}

#ifndef ONLINE_JUDGE
printf("time = %d.\n", (int)clock());
#endif

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: