例题7-9 万圣节后的早晨 UVa1601

来源:互联网 发布:泽野螳螂 知乎 编辑:程序博客网 时间:2024/05/20 06:30

【题目链接】点击打开链接

【题意】w*h(w,h <= 16)网格中有n(n<=3)个小写字母(代表鬼),要求把它们分别移动到对应的大写字母里。每一步可以有多个鬼移动(均为往上下左右4个方向之1移动),但每一步结束之后,任何两个鬼不能占用同一个位置,也不能在一步之内交换位置。

【解题方法】方法是把所有可以移动的格子找出来建立一张图,就是把障碍物给删除,统计每个可以空格或者有鬼的格子可以移动到哪些格子,这样在判断的时候就节省了许多时间。然后bfs找最短路。具体可以看紫书206页,书上还提到了可以用双向BFS的方法,现在不会。


【AC代码】


////Created by BLUEBUFF 2016/1/9//Copyright (c) 2016 BLUEBUFF.All Rights Reserved//#pragma comment(linker,"/STACK:102400000,102400000")#include <ext/pb_ds/assoc_container.hpp>#include <ext/pb_ds/tree_policy.hpp>#include <ext/pb_ds/hash_policy.hpp>#include <set>#include <map>#include <queue>#include <stack>#include <cmath>#include <cstdio>#include <time.h>#include <cstdlib>#include <cstring>#include <complex>#include <sstream> //isstringstream#include <iostream>#include <algorithm>using namespace std;//using namespace __gnu_pbds;typedef long long LL;typedef pair<int, LL> pp;#define REP1(i, a, b) for(int i = a; i < b; i++)#define REP2(i, a, b) for(int i = a; i <= b; i++)#define REP3(i, a, b) for(int i = a; i >= b; i--)#define CLR(a, b)     memset(a, b, sizeof(a))#define MP(x, y)      make_pair(x,y)template <class T1, class T2>inline void getmax(T1 &a, T2 b) { if (b>a)a = b; }template <class T1, class T2>inline void getmin(T1 &a, T2 b) { if (b<a)a = b; }const int maxn = 20;const int maxm = 300;const int maxs = 10;const int maxp = 1e3 + 10;const int INF  = 1e9;const int UNF  = -1e9;const int mod  = 1e9 + 7;const double PI = acos(-1);//headint getnum(int a, int b, int c){ //编码    return (a << 16) | (b << 8) | c;}int ok(int a, int b, int a1, int b1){ //两种非法的情况    return ((a1 == b1) || (a1 == b && b1 == a));}int dir[5][2] = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}, {0, 0}};int id[maxn][maxn], G[maxm][5]; //由于相邻节点最多5个,包含自身int st[3], en[3]; //st存放起始位置,en存放结束位置int edge[maxm], d[maxm][maxm][maxm];//edge数组存放第i个结点具有的相邻结点数目int w, h, n, cnt;char M[maxn][maxn]; //原地图void bfs(){    queue <int> q;    memset(d, -1, sizeof(d));    q.push(getnum(st[0], st[1], st[2]));    d[st[0]][st[1]][st[2]] = 0;    while(!q.empty())    {        int u = q.front(); q.pop();        int a = (u >> 16) & 255, b = (u >> 8) & 255, c = u & 255; //解码各个鬼的位置        if(a == en[0] && b == en[1] && c == en[2]) return; //找个目标状态        for(int i = 1; i <= edge[a]; i++){            int a1 = G[a][i];            for(int j = 1; j <= edge[b]; j++){                int b1 = G[b][j];                if(ok(a, b, a1, b1)) continue;                for(int k = 1; k <= edge[c]; k++){                    int c1 = G[c][k];                    if(ok(a, c, a1, c1)) continue;                    if(ok(b, c, b1, c1)) continue;                    if(d[a1][b1][c1] == -1){                        d[a1][b1][c1] = d[a][b][c] + 1;                        q.push(getnum(a1, b1, c1));                    }                }            }        }    }}int main(){    while(scanf("%d%d%d", &w, &h, &n) != EOF && n)    {        char c = getchar();        while(c != '\n') c = getchar();        REP2(i, 1, h){            fgets(M[i] + 1, 20, stdin);        }        cnt = 0;        int x[maxm], y[maxm];        REP2(i, 1, h){            REP2(j, 1, w){                if(M[i][j] != '#'){                    id[i][j] = ++cnt;//利用矩阵存稀疏图,cnt是每个结点的序号,也代表了最终的结点数                    x[cnt] = i;                    y[cnt] = j;                    if('a' <= M[i][j] && M[i][j] <= 'c'){                        st[M[i][j] - 'a'] = cnt; //找每一个鬼                    }                    if('A' <= M[i][j] && M[i][j] <= 'C'){                        en[M[i][j] - 'A'] = cnt; //找目标位置                    }                }            }        }        REP2(i, 1, cnt){            edge[i] = 0;            REP1(j, 0, 5){                int dx = x[i] + dir[j][0];                int dy = y[i] + dir[j][1];                if(M[dx][dy] != '#'){                    G[i][++edge[i]] = id[dx][dy];//寻找每个结点的相邻结点,包括自己                }            }        }        if(n <= 2){            edge[++cnt] = 1;            G[cnt][1] = cnt;            st[2] = en[2] = cnt;        }        if(n <= 1){            edge[++cnt] = 1;            G[cnt][1] = cnt;            st[1] = en[1] = cnt;        }        bfs();        printf("%d\n", d[en[0]][en[1]][en[2]]);    }    return 0;}



0 0
原创粉丝点击