UVa 1601 万圣节后的早晨

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4476

题意:给出w*h的网格,相当于迷宫,有大写字母和小写字母,算出小写字母走到大写字母状态时的最少步数。

思路:建立新图,然后再bfs。

  1 #include<iostream>
  2 #include<string>
  3 #include<cstring>
  4 #include<queue>
  5 using namespace std;
  6 
  7 const int maxn = 16 * 16;
  8 
  9 char map[20][20];
 10 int w, h, n;
 11 int cnt; //非#结点个数
 12 int x[maxn], y[maxn];
 13 int s[3], t[3];  //记录初末位置
 14 int deg[maxn];  //记录每个格子相连的格子数
 15 int G[maxn][maxn];  //记录每个格子可以走的位置
 16 int new_map[20][20]; //新图
 17 int d[maxn][maxn][maxn]; //记录步数
 18 
 19 int dx[] = { 0, 1, -1, 0, 0 };
 20 int dy[] = { 0, 0, 0, 1, -1 };
 21 
 22 int ID(int x, int y, int z)   //二进制压缩存储,方便进出队列
 23 {
 24     return (x << 16) | (y << 8) | z;
 25 }
 26 
 27 bool judge(int a, int b, int a2, int b2)
 28 {
 29     return a2 == b2 || (a2 == b && b2 == a);
 30 }
 31 
 32 void bfs()
 33 {
 34     queue<int> q;
 35     memset(d, -1, sizeof(d));
 36     q.push(ID(s[0], s[1], s[2]));  //二进制压缩后再进队
 37     d[s[0]][s[1]][s[2]] = 0;
 38     while (!q.empty())
 39     {
 40         int u = q.front();
 41         q.pop();
 42         int a = (u >> 16) & 0xff; //得到压缩前的数据
 43         int b = (u >> 8) & 0xff;
 44         int c = u & 0xff;
 45         if (a==t[0] && b==t[1] && c==t[2]) //得到目标状态
 46         {
 47             cout << d[a][b][c] << endl;
 48             return;
 49         }
 50         for (int i = 0; i < deg[a]; i++)
 51         {
 52             int a2 = G[a][i];
 53             for (int j = 0; j < deg[b]; j++)
 54             {
 55                 int b2 = G[b][j];
 56                 if (judge(a, b, a2, b2))  continue; //删去不符合条件的走法
 57                 for (int k = 0; k < deg[c]; k++)
 58                 {
 59                     int c2 = G[c][k];
 60                     if (judge(a, c, a2, c2))  continue;
 61                     if (judge(b, c, b2, c2))  continue;
 62                     if (d[a2][b2][c2] != -1) continue;
 63                     d[a2][b2][c2] = d[a][b][c] + 1;
 64                     q.push(ID(a2, b2, c2));
 65                 }
 66             }
 67         }
 68     }
 69 }
 70 
 71 
 72 int main()
 73 {
 74     //freopen("D:\txt.txt", "r", stdin);
 75     while (cin>>w>>h>>n && n)
 76     {
 77         getchar();
 78         cnt = 0;   //记录非#结点个数
 79         memset(map, 0, sizeof(map));
 80         memset(deg, 0, sizeof(deg));
 81         for (int i = 0; i < h; i++)
 82         {
 83             fgets(map[i], 20, stdin);
 84             for (int j = 0; j < w; j++)
 85             {
 86                 if (map[i][j] != '#')
 87                 {
 88                     x[cnt] = i;
 89                     y[cnt] = j;
 90                     new_map[i][j] = cnt; //建图记录结点
 91                     if (map[i][j] >= 'a' && map[i][j] <= 'c')  s[map[i][j] - 'a'] = cnt;
 92                     if (map[i][j] >= 'A' && map[i][j] <= 'C')  t[map[i][j] - 'A'] = cnt;
 93                     cnt++;
 94                 }
 95             }
 96         }
 97 
 98         for (int i = 0; i < cnt; i++)
 99         {
100             for (int k = 0; k < 5; k++)
101             {
102                 int xx = x[i] + dx[k];
103                 int yy = y[i] + dy[k];
104                 if (map[xx][yy] != '#')  G[i][deg[i]++] = new_map[xx][yy]; //如果可以走,则将第i个点的第deg[i]个方向的下一个格子记录
105             }
106         }
107 
108         //如果不满三个鬼,强行添加结点使之构成三个结点
109 
110         if (n <= 2) //添加虚拟结点
111         {
112             deg[cnt] = 1; G[cnt][0] = cnt; s[2] = t[2] = cnt++;
113         }
114         if (n <= 1)
115         {
116             deg[cnt] = 1; G[cnt][0] = cnt; s[1] = t[1] = cnt++;
117         }
118 
119         bfs();
120     }
121     return 0;
122 }
原文地址:https://www.cnblogs.com/zyb993963526/p/6337291.html