UVA1601-双向广度优先搜索

Posted savennist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA1601-双向广度优先搜索相关的知识,希望对你有一定的参考价值。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <queue>
  4 #include <cstring>
  5 using namespace std;
  6 
  7 int w, h, n, s[3], t[3];
  8 char dataset[20][20];
  9 int G[200][5], vis[200][200][200], dist[200][200][200];
 10 int deg[200]; 
 11 int dx[] = {0, -1, 1, 0, 0};//这里包含了不移动的情形
 12 int dy[] = {0, 0, 0, -1, 1};
 13 
 14 inline int ID(int a, int b, int c)
 15 {
 16     return (a << 16) | (b << 8) | c;
 17 }//一种看起来屌炸天的数据整合方式
 18 
 19 inline bool conflict(int a, int b, int a2, int b2)
 20 {
 21     return ((a2 == b2) || (a == b2 && b == a2));
 22     //前者是两者运动到同一位置,后者是两者同时交换位置
 23 }
 24 
 25 int bfs()
 26 {
 27     queue<int> q;
 28     q.push(ID(s[0], s[1], s[2]));
 29     dist[s[0]][s[1]][s[2]] = 0;//dist初始值是-1,这里的0是做标记
 30     while(!q.empty())
 31     {
 32         int u = q.front();  q.pop();
 33         int a = (u >> 16) & 0xff, b = (u >> 8) & 0xff, c = u & 0xff;
 34         //一种看起来屌炸天的数据整合方式,记住!!
 35         if(a == t[0] && b == t[1] && c == t[2]) return dist[a][b][c];
 36         //a对应了main中的cnt编号,它并没有直接验证横竖坐标而是验证了其编号
 37         for(int i = 0; i < deg[a]; i++)
 38         {//deg[a]是cnt编号为a的字母在该点的所有可行的运动方向的个数,遍历所有可行方向
 39             int a2 = G[a][i];
 40         //cnt编号为a的字母运动结果a2
 41             for(int j = 0; j < deg[b]; j++)
 42             {
 43                 int b2 = G[b][j];
 44         //cnt编号为b的字母运动结果b2
 45                 if(conflict(a, b, a2, b2))continue;
 46                 //对于产生的运动冲突,由第二个字母做出变换方向的让步
 47                 for(int k = 0; k < deg[c]; k++)
 48                 {
 49                     int c2 = G[c][k];
 50         //cnt编号为c的字母运动结果c2
 51                     if(conflict(a, c, a2, c2) || conflict(b, c, b2, c2))continue;
 52                     if(dist[a2][b2][c2] == -1)
 53                     {
 54                         dist[a2][b2][c2] = dist[a][b][c] + 1;
 55                         //这是记录步数
 56                         q.push(ID(a2, b2, c2));
 57                     }
 58                 }
 59             }
 60         }
 61     }
 62     return -1;
 63 }
 64 
 65 int main() {
 66     //freopen("input.txt", "r", stdin);
 67     while(~scanf("%d%d%d
", &w, &h, &n) && n)
 68     {
 69         for(int i = 0; i < h; i++)  fgets(dataset[i], 20, stdin);
 70         //输入图
 71         int cnt = 0, x[200], y[200], id[20][20];
 72         for(int i = 0; i < h; i++)
 73         for(int j = 0; j < w; j++)
 74         {
 75             if(dataset[i][j] != #)//对于所有的可行动的位置都由一个cnt编号
 76             {
 77                 //s->cnt->x与y 这是一种值得借鉴的对应关系
 78                 x[cnt] = i; y[cnt] = j; id[i][j] = cnt;//在图中赋予可行动位置唯一的id
 79                 if(islower(dataset[i][j]))  s[dataset[i][j] - a] = cnt;
 80                 else if(isupper(dataset[i][j])) t[dataset[i][j] - A] = cnt;
 81                 cnt++;//所有的坐标均被分配到x与y数组中,cnt是唯一的确认,将两个数据映射成了一个数据!!!
 82             }//记录bfs路径的起点与终点的信息 s数组是起点,t数组是终点,
 83         }
 84         for(int i = 0; i < cnt; i++)//对应每一个位置
 85         {
 86             deg[i] = 0;
 87             for(int j = 0; j < 5; j++)//对应不同的方向且考虑了不移动的情形
 88             {
 89                 int nx = x[i] + dx[j];  int ny = y[i] + dy[j];
 90                 if(dataset[nx][ny] != #)  G[i][deg[i]++] = id[nx][ny];
 91                 //G[cnt编号][方向]
 92             }
 93         }
 94         //对于所有的位置的每一个可行的方向都记录下来
 95         if(n <= 2)  { deg[cnt] = 1; G[cnt][0] = cnt;    s[2] = t[2] = cnt++; }
 96         if(n <= 1)  { deg[cnt] = 1; G[cnt][0] = cnt;    s[1] = t[1] = cnt++; }//这里似乎是控制移动对象个数
 97         memset(dist, -1, sizeof(dist));
 98         printf("%d
", bfs());
 99     }
100     return 0;
101 }

这不是我的代码,这是一个很好的代码,下面有几个方面值得借鉴学习:

1、数据结构设计十分巧妙,仅仅使用普通的数组建立的结构使得数据的查找与变换十分快捷方便

2、利用这个代码中的映射结构,提前准备好每个点可行的方向,这个可以用于平时的bfs或dfs中

以上是关于UVA1601-双向广度优先搜索的主要内容,如果未能解决你的问题,请参考以下文章

广度优先搜索

八数码问题——双向广度优先搜索解决

UVa1601 The Morning after Halloween(双向bfs)

常见搜索算法:深度优先和广度优先搜索

常见搜索算法:深度优先和广度优先搜索

UVA 1601 双向BFS