1601 - The Morning after Halloween
来源:互联网 发布:ios音乐制作软件 编辑:程序博客网 时间:2024/06/07 13:04
PS:因为该题排版较麻烦,这里给出OJ网址:UVa 1601 - The Morning after Halloween
w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼)。要求把它们分别移动到对应的大写字母里。每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占用同一个位置,也不能在一步之内交换位置。
输入保证所有空格连通,所有障碍格也连通,且任何一个2*2子网格中至少有一个障碍格。输出最少的步数。输入保证有解。
RuJia的写法非常精巧,理解不易
// UVa1601 The Morning after Halloween// Rujia Liu// This code implements the simpliest yet efficient-enough algorithm I'm aware of// Readers are encouraged to experiment on other algorithms (especially for better efficiency!)#include<cstdio>#include<cstring>#include<cctype>#include<queue>using namespace std;const int maxs = 20;const int maxn = 150; // 75% cells plus 2 fake nodesconst int dx[]={1,-1,0,0,0}; // 4 moves, plus "no move"const int dy[]={0,0,1,-1,0};inline int ID(int a, int b, int c) { return (a<<16)|(b<<8)|c;}int s[3], t[3]; // starting/ending position of each ghostint deg[maxn], G[maxn][5]; // target cells for each move (including "no move")inline bool conflict(int a, int b, int a2, int b2) { return a2 == b2 || (a2 == b && b2 == a);}int d[maxn][maxn][maxn]; // distance from starting stateint bfs() { queue<int> q; memset(d, -1, sizeof(d)); q.push(ID(s[0], s[1], s[2])); // starting node d[s[0]][s[1]][s[2]] = 0; while(!q.empty()) { int u = q.front(); q.pop(); int a = (u>>16)&0xff, b = (u>>8)&0xff, c = u&0xff; if(a == t[0] && b == t[1] && c == t[2]) return d[a][b][c]; // solution found for(int i = 0; i < deg[a]; i++) { int a2 = G[a][i]; for(int j = 0; j < deg[b]; j++) { int b2 = G[b][j]; if(conflict(a, b, a2, b2)) continue; for(int k = 0; k < deg[c]; k++) { int c2 = G[c][k]; if(conflict(a, c, a2, c2)) continue; if(conflict(b, c, b2, c2)) continue; if(d[a2][b2][c2] != -1) continue; d[a2][b2][c2] = d[a][b][c]+1; q.push(ID(a2, b2, c2)); } } } } return -1;}int main() { int w, h, n; while(scanf("%d%d%d\n", &w, &h, &n) == 3 && n) { char maze[20][20]; // 读入floor for(int i = 0; i < h; i++) fgets(maze[i], 20, stdin); // extract empty cells int cnt, x[maxn], y[maxn], id[maxs][maxs]; // cnt is the number of empty cells cnt = 0; for(int i = 0; i < h; i++) for(int j = 0; j < w; j++) if(maze[i][j] != '#') { x[cnt] = i; y[cnt] = j; id[i][j] = cnt; if(islower(maze[i][j])) s[maze[i][j] - 'a'] = cnt; else if(isupper(maze[i][j])) t[maze[i][j] - 'A'] = cnt; cnt++; } // build a graph of empty cells for(int i = 0; i < cnt; i++) { deg[i] = 0; for(int dir = 0; dir < 5; dir++) { int nx = x[i]+dx[dir], ny = y[i]+dy[dir]; // "Outermost cells of a map are walls" means we don't need to check out-of-bound if(maze[nx][ny] != '#') G[i][deg[i]++] = id[nx][ny]; } } // add fakes nodes so that in each case we have 3 ghosts. this makes the code shorter if(n <= 2) { deg[cnt] = 1; G[cnt][0] = cnt; s[2] = t[2] = cnt++; } if(n <= 1) { deg[cnt] = 1; G[cnt][0] = cnt; s[1] = t[1] = cnt++; } printf("%d\n", bfs()); } return 0;}
自己写的表示超时了
//#define LOCAL#include <cstdio>#include <iostream>#include <string>#include <cstring>#include <queue>#include <algorithm>#include <set>#include <vector>using namespace std;const int maxH = 16 + 5;// 网格宽,长,ghost数量int w, h, n;// 初始状态int start[maxH][maxH];// 初始状态的a,b,c的位置int ar = 0, ac = 0, br = 0, bc = 0, cr = 0, cc = 0;// 目标状态int goal[maxH][maxH];// 目标状态的a,b,c的位置int are = 0, ace = 0, bre = 0, bce = 0, cre = 0, cce = 0;// 是否走廊int isCorridor[maxH][maxH];struct Node { // 状态 int v[maxH][maxH]; // 当前的a,b,c的位置 int ar, ac, br, bc, cr, cc; // 距离 int dist;};// 移动方位, 上下左右,不动int dx[] = {-1, 1, 0, 0, 0};int dy[] = { 0, 0, -1, 1, 0};const int haseSize = 100003;vector<int> head[haseSize];void init_lookup_table2() { for(int i = 0; i < haseSize; i++) { head[i].clear(); }}int myhash(int sum) { return sum % haseSize;}bool try_insert2(const Node &u) { int sum = 0; sum += (u.ac << 20); sum += (u.ar << 16); sum += (u.bc << 12); sum += (u.br << 8); sum += (u.cr << 4); sum += (u.cc); int h = myhash(sum); // 开放定址法 for(int i = 0; i < head[h].size(); i++) { if(head[h][i] == sum) { return false; } } head[h].push_back(sum); return true;}set<long> vis;// 初始化访问表void init_lookup_table() { vis.clear();}// 尝试插入bool try_insert(const Node &u) { long sum = 0; sum += u.ac * 10000000000; sum += u.ar * 100000000; sum += u.bc * 1000000; sum += u.br * 10000; sum += u.cr * 100; sum += u.cc; if(vis.count(sum)) { return false; } vis.insert(sum); return 1;}void solve() {// for(int i = 0; i < h; i++) {// for(int j = 0; j < w; j++) {// if(start[i][j] == 0) {// cout << "#";// } else if(start[i][j] == 1) {// cout << " ";// } else if(start[i][j] == 'a') {// cout << "a";// } else if(start[i][j] == 'b') {// cout << "b";// } else if(start[i][j] == 'c') {// cout << "c";// }// }// cout << endl;// }// cout << endl;// for(int i = 0; i < h; i++) {// for(int j = 0; j < w; j++) {// if(isCorridor[i][j] == 0) {// cout << "#";// } else if(isCorridor[i][j] == 1) {// cout << " ";// }// }// cout << endl;// }// cout << "(" << ar << "," << ac << ") ("// << br << "," << bc << ") ("// << cr << "," << cc << ")" << endl;// cout << "(" << are << "," << ace << ") ("// << bre << "," << bce << ") ("// << cre << "," << cce << ")" << endl; // 初始化访问表 init_lookup_table2(); // 初始节点 Node sta; memcpy(&sta.v, &start, sizeof(start)); sta.dist = 0; sta.ar = ar; sta.br = br; sta.cr = cr; sta.ac = ac; sta.bc = bc; sta.cc = cc; queue<Node> q; q.push(sta); // BFS while(!q.empty()) { Node u = q.front(); q.pop();// cout << "(" << u.ar << "," << u.ac << ") ("// << u.br << "," << u.bc << ") ("// << u.cr << "," << u.cc << ")" << endl; // 找到终点状态,退出 if(u.ar == are && u.ac == ace && u.br == bre && u.bc == bce && u.cr == cre && u.cc == cce) { cout << u.dist << endl; return; } // 根据goast数目确定循环层数 if(n == 1) { for(int i = 0; i < 5; i++) { // 下一个位置 int nextAR = u.ar + dx[i]; int nextAC = u.ac + dy[i]; // 走廊 if(isCorridor[nextAR][nextAC]) { Node u2; memcpy(&u2, &u, sizeof(u)); // 距离加一 u2.dist++; // 交换goast与空格位置 swap(u2.v[u2.ar][u2.ac],u2.v[nextAR][nextAC]); u2.ar = nextAR; u2.ac = nextAC; if(try_insert2(u2)) { q.push(u2); } } } } else if(n == 2) { for(int i = 0; i < 5; i++) { for(int j = 0; j < 5; j++) { // 下一个位置 int nextAR = u.ar + dx[i]; int nextAC = u.ac + dy[i]; int nextBR = u.br + dx[j]; int nextBC = u.bc + dy[j]; // 走廊 if(isCorridor[nextAR][nextAC] && isCorridor[nextBR][nextBC]) { // 不能在同一个位置,不能交换位置 if((nextAR == nextBR && nextAC == nextBC) || (nextAR == u.br && nextAC == u.bc && nextBR == u.ar && nextBC == u.ac)) { continue; } else { Node u2; memcpy(&u2, &u, sizeof(u)); // 距离加一 u2.dist++; // 交换goast与空格位置 swap(u2.v[u2.ar][u2.ac],u2.v[nextAR][nextAC]); swap(u2.v[u2.br][u2.bc],u2.v[nextBR][nextBC]); u2.ar = nextAR; u2.ac = nextAC; u2.br = nextBR; u2.bc = nextBC; if(try_insert2(u2)) { q.push(u2); } } } } } } else if(n == 3) { for(int i = 0; i < 5; i++) { for(int j = 0; j < 5; j++) { for(int k = 0; k < 5; k++) { // 下一个位置 int nextAR = u.ar + dx[i]; int nextAC = u.ac + dy[i]; int nextBR = u.br + dx[j]; int nextBC = u.bc + dy[j]; int nextCR = u.cr + dx[k]; int nextCC = u.cc + dy[k]; // 走廊 if(isCorridor[nextAR][nextAC] && isCorridor[nextBR][nextBC] && isCorridor[nextCR][nextCC]) { // 不能在同一个位置,不能交换位置 if((nextAR == nextBR && nextAC == nextBC) || (nextAR == nextCR && nextAC == nextCC) || (nextBR == nextCR && nextBC == nextCC) || (nextAR == u.br && nextAC == u.bc && nextBR == u.ar && nextBC == u.ac) || (nextAR == u.cr && nextAC == u.cc && nextCR == u.ar && nextCC == u.ac) || (nextBR == u.cr && nextBC == u.cc && nextCR == u.br && nextCC == u.bc)) { continue; } else { Node u2; memcpy(&u2, &u, sizeof(u)); // 距离加一 u2.dist++; // 交换goast与空格位置 swap(u2.v[u2.ar][u2.ac],u2.v[nextAR][nextAC]); swap(u2.v[u2.br][u2.bc],u2.v[nextBR][nextBC]); swap(u2.v[u2.cr][u2.cc],u2.v[nextCR][nextCC]); u2.ar = nextAR; u2.ac = nextAC; u2.br = nextBR; u2.bc = nextBC; u2.cr = nextCR; u2.cc = nextCC; if(try_insert2(u2)) {// cout << "(" << u.ar << "," << u.ac << ") ("// << nextAR << "," << nextAC << ")\t("// << u.br << "," << u.bc << ") ("// << nextBR << "," << nextBC << ")\t("// << u.cr << "," << u.cc << ") ("// << nextCR << "," << nextCC << ")" << endl; q.push(u2); } } } } } } } }}int main() { #ifdef LOCAL freopen("data.1601.in", "r", stdin); freopen("data.1601.out", "w", stdout); #endif // LOCAL while(cin >> w >> h >> n) { if(!w) { break; } // 多少行 for(int i = 0; i < h; i++) { } memset(start, 0, sizeof(start)); memset(goal, 0, sizeof(goal)); memset(isCorridor, 0, sizeof(isCorridor)); string s; getline(cin, s); for(int i = 0; i < h; i++) { getline(cin, s); for(int j = 0; j < s.length(); j++) { switch(s[j]) { // 走廊 case ' ' : { start[i][j] = 1; goal[i][j] = 1; isCorridor[i][j] = 1; break; } // 目标位置 case 'A' : { goal[i][j] = 'a'; start[i][j] = 1; isCorridor[i][j] = 1; are = i; ace = j; break; } case 'B' : { goal[i][j] = 'b'; start[i][j] = 1; isCorridor[i][j] = 1; bre = i; bce = j; break; } case 'C' : { goal[i][j] = 'c'; start[i][j] = 1; isCorridor[i][j] = 1; cre = i; cce = j; break; } // 初始位置 case 'a' : { start[i][j] = 'a'; isCorridor[i][j] = 1; ar = i; ac = j; break; } case 'b' : { start[i][j] = 'b'; isCorridor[i][j] = 1; br = i; bc = j; break; } case 'c' : { start[i][j] = 'c'; isCorridor[i][j] = 1; cr = i; cc = j; break; } } } } solve(); } return 0;}
0 0
- 1601 - The Morning after Halloween
- 1601 - The Morning after Halloween
- 1601 - The Morning after Halloween
- 1601 - The Morning after Halloween(BFS)
- 隐式图--UVA - 1601 The Morning after Halloween
- UVa OJ 1601 - The Morning after Halloween
- UVA 1601 The Morning after Halloween [DBFS]
- uva 1601 The Morning after Halloween
- uva 1601 The Morning after Halloween code2
- UVa1601-The Morning after Halloween
- UVA1601 The Morning after Halloween
- The Morning after Halloween(POJ
- The Morning after Halloween UVA
- The Morning after Halloween UVA
- UVa #1601 The Morning after Halloween (例题7-9)
- UVa 1601 - The Morning after Halloween(单向BFS版)
- UVa 1601 - The Morning after Halloween(双向BFS版)
- UVa 1601:The Morning after Halloween(BFS)
- github部署Heroku
- 通过自定义注解,实现简单的orm持久化类
- 架构模式
- MLlib分类算法实战演练--Spark学习(机器学习)
- Cuda(2):新建项目
- 1601 - The Morning after Halloween
- 设计模式
- Unity3D添加天空盒子
- iOS 开发遇到问题
- RenderScript 让你的Android计算速度快的飞上天!
- vertica-创建超级用户
- hibernate笔记
- 没有谁是一座孤岛——《岛上书店》
- 使用Python 进行socket编程