【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. 代码
$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; }
相关文章推荐
- 函数指针(之一)——在排序算法中的应用
- 控制台版2048 version_1.0总结
- 学以致用之冒泡排序
- 【Design Pattern】外观模式 Facade
- 新起点
- ie11不再支持attachEvent事件
- gnuplot画图一
- 三色球问题
- OpenCV基础
- collectionview实现无限轮播
- NYOJ----776删除元素
- C# byte数组与Image相互转换的方法
- ubuntu虚拟机配置nfs服务器软件的步骤
- C/C++语言void及void指针深层探索
- 几种排序算法的简单总结
- auto format code in visual studio
- 基础练习 数的读法
- 观察者模式
- Druid连接池及监控在spring中的配置
- 基础练习 Sine之舞