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
原创粉丝点击