题解【P1778 万圣节后的早晨】

· · 题解

题面可以看这里

思路:

代码:

普通 BFS:

#include <bits/stdc++.h>
using namespace std;
int G[150][5], deg[150], st[3], ed[3], d[150][150][150];
//deg: 每个结点的出度(最大为 5,四个方向和原地不动)
//d: 每个状态到起点状态的距离
int mm(int a, int b, int c) {return (a<<16) | (b<<8) | c;}// 二进制状态压缩
bool ct(int a, int b, int x, int y){return b == y || (a == y && b == x);}
// 返回 a -> b 的鬼和 x -> y 的鬼路线是否冲突
int bfs()
{
    memset(&d[0][0][0], -1, sizeof d);
    queue <int> q;
    q.push(mm(st[0], st[1], st[2]));
    d[st[0]][st[1]][st[2]] = 0;
    while(!q.empty())
    {
        int x = q.front(), a = x >> 16, b = (x >> 8) & 0xff, c = x & 0xff;
        q.pop();
        if(a == ed[0] && b == ed[1] && c == ed[2]) return d[a][b][c];
        for(int i = 0; i < deg[a]; ++i)
            for(int j = 0; j < deg[b]; ++j)
            {
                if(ct(a, G[a][i], b, G[b][j])) continue;
                for(int k = 0; k < deg[c]; ++k)
                {
                    if(ct(a, G[a][i], c, G[c][k]) || ct(b, G[b][j], c, G[c][k]) || d[G[a][i]][G[b][j]][G[c][k]] != -1) continue;
                    d[G[a][i]][G[b][j]][G[c][k]] = d[a][b][c]+1;
                    q.push(mm(G[a][i], G[b][j], G[c][k]));
                }
            }
    }
    return -1;
}
int main()
{
    int w, h, n;
    char s[20][20];
    while(scanf("%d%d%d", &w, &h, &n), w || h || n)
    {
        int cnt = 0, id[20][20]; // id: 空格在图中结点编号
        memset(deg, 0, sizeof deg);
        for(int i = 0; i < h; ++i)
        { // 处理好输入,顺便建图
            scanf(" ");
            for(int j = 0; j < w; ++j)
            {
                s[i][j] = getchar();
                if(s[i][j] != '#')
                {
                    id[i][j] = ++cnt;
                    G[cnt][deg[cnt]++] = cnt;
                    if(s[i-1][j] != '#'){G[cnt][deg[cnt]++] = id[i-1][j]; G[id[i-1][j]][deg[id[i-1][j]]++] = cnt;}
                    if(s[i][j-1] != '#'){G[cnt][deg[cnt]++] = id[i][j-1]; G[id[i][j-1]][deg[id[i][j-1]]++] = cnt;}
                    if(islower(s[i][j])) st[s[i][j]-'a'] = cnt;
                    else if(isupper(s[i][j])) ed[s[i][j]-'A'] = cnt;
                }
            }
        }
        /* 虚拟结点 */
        if(n <= 2) {deg[++cnt] = 1; G[cnt][0] = cnt; st[2] = ed[2] = cnt;}
        if(n == 1) {deg[++cnt] = 1; G[cnt][0] = cnt; st[1] = ed[1] = cnt;} 
        printf("%d\n", bfs());
    }
    return 0;
}

双向 BFS:

#include <bits/stdc++.h>
using namespace std;
int G[150][5], deg[150], st[3], ed[3], d1[150][150][150], d2[150][150][150];
int mm(int a, int b, int c) {return (a<<16) | (b<<8) | c;}
bool ct(int a, int b, int x, int y){return b == y || (a == y && b == x);}
int bfs()
{
    memset(&d1[0][0][0], -1, sizeof d1);
    memset(&d2[0][0][0], -1, sizeof d2);
    queue <int> q1, q2;
    q1.push(mm(st[0], st[1], st[2]));
    d1[st[0]][st[1]][st[2]] = 0;
    q2.push(mm(ed[0], ed[1], ed[2]));
    int n1, n2, x1, x2;
    n2 = n1 = 1;
    x1 = x2 = 0;
    do {
        if(!n2 || x1 < x2)
        {
            int x = q1.front(), a = x >> 16, b = (x >> 8) & 0xff, c = x & 0xff;
            q1.pop(); --n1;
            if(d2[a][b][c] != -1) return d1[a][b][c] + d2[a][b][c];
            if(d1[a][b][c] > x1){++x1; q1.push(x); ++n1; continue;}
            for(int i = 0; i < deg[a]; ++i)
                for(int j = 0; j < deg[b]; ++j)
                {
                    if(ct(a, G[a][i], b, G[b][j])) continue;
                    for(int k = 0; k < deg[c]; ++k)
                    {
                        if(ct(a, G[a][i], c, G[c][k]) || ct(b, G[b][j], c, G[c][k]) || d1[G[a][i]][G[b][j]][G[c][k]] != -1) continue;
                        d1[G[a][i]][G[b][j]][G[c][k]] = d1[a][b][c]+1;
                        q1.push(mm(G[a][i], G[b][j], G[c][k]));
                        ++n1;
                    }
                }
        }
        else
        {
            int x = q2.front(), a = x >> 16, b = (x >> 8) & 0xff, c = x & 0xff;
            q2.pop(); --n2;
            if(d1[a][b][c] != -1) return d1[a][b][c] + d2[a][b][c];
            if(d2[a][b][c] > x2){++x2; q2.push(x); ++n2; continue;}
            for(int i = 0; i < deg[a]; ++i)
                for(int j = 0; j < deg[b]; ++j)
                {
                    if(ct(a, G[a][i], b, G[b][j])) continue;
                    for(int k = 0; k < deg[c]; ++k)
                    {
                        if(ct(a, G[a][i], c, G[c][k]) || ct(b, G[b][j], c, G[c][k]) || d2[G[a][i]][G[b][j]][G[c][k]] != -1) continue;
                        d2[G[a][i]][G[b][j]][G[c][k]] = d2[a][b][c]+1;
                        q2.push(mm(G[a][i], G[b][j], G[c][k]));
                        ++n2;
                    }
                }
        }
    } while(n1 || n2);
    return -1;
}
int main()
{
    int w, h, n;
    char s[20][20];
    while(scanf("%d%d%d", &w, &h, &n), w || h || n)
    {
        int cnt = 0, id[20][20];
        memset(deg, 0, sizeof deg);
        for(int i = 0; i < h; ++i)
        {
            scanf(" ");
            for(int j = 0; j < w; ++j)
            {
                s[i][j] = getchar();
                if(s[i][j] != '#')
                {
                    id[i][j] = ++cnt;
                    G[cnt][deg[cnt]++] = cnt;
                    if(s[i-1][j] != '#'){G[cnt][deg[cnt]++] = id[i-1][j]; G[id[i-1][j]][deg[id[i-1][j]]++] = cnt;}
                    if(s[i][j-1] != '#'){G[cnt][deg[cnt]++] = id[i][j-1]; G[id[i][j-1]][deg[id[i][j-1]]++] = cnt;}
                    if(islower(s[i][j])) st[s[i][j]-'a'] = cnt;
                    else if(isupper(s[i][j])) ed[s[i][j]-'A'] = cnt;
                }
            }
        }
        if(n <= 2) {deg[++cnt] = 1; G[cnt][0] = cnt; st[2] = ed[2] = cnt;}
        if(n == 1) {deg[++cnt] = 1; G[cnt][0] = cnt; st[1] = ed[1] = cnt;}
        printf("%d\n", bfs());
    }
    return 0;
}

双倍经验:UVA1601。