• UVA1601-The Morning after Halloween(双向BFS)


    Problem UVA1601-The Morning after Halloween

    Accept: 289 Submit: 3136

    Time Limit: 12000 mSec

     Problem Description

     Input

     Output

    For each dataset in the input, one line containing the smallest number of steps to restore ghosts into the positions where they are supposed to be should be output. An output line should not contain extra characters such as spaces.

     Sample Input

     

     Sample Ouput

    7

    36

    77

    题解:双向BFS经典题目。

    抛开双向BFS,这个题的预处理也很值得学习。节点个数太多16*16=256,并且有三个鬼,所以状态总数几乎是256^3,不管是时间还是空间,肯定都要炸,所以就要把状态算的精确一些,省去一些不可能的情况,首先最外层都是'#',这样这个图就变成了最大14*14 = 196,还是有点大,注意题目条件,每2*2中至少有一个障碍,所以这196个点至多有75%是空格,196*0.75 = 147。这就差不多了,由于后面可能有加点的操作,不过最多加2个点,也就是说总数不会超过150,这个数字就比较理想了,时间上和空间上都不错。判重的问题,刚才分析过了,每个鬼能够出现的格子数目不超过150,八位二进制数就能表示,因此三个就可以用24位二进制数表示,和int还有一段距离,所以转换成一个int型整数判重是再好不过的了。将所有空格连接起来用的是类似邻接表的操作,不过lrj没有用vector,可能还是效率原因吧。

    之后就是双向BFS的模板了,两个队列,分别入队出发点和终点,vis数组肯定是三维的,只是原来的0、1变成了现在的0、1、2,因为要区分是在哪一边扩展的过程中遍历到的这个点。当一个点在两个队列中都出现了,就说明找到了,返回dis的和,别忘了+1.还有一个需要注意的是双向BFS每次扩展一层而不是扩展一个节点。原因参考下面的链接:

    http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx

    先来一个单向BFS,680ms

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #include <queue>
     6 using namespace std;
     7 
     8 const int maxs = 20;
     9 const int maxn = 150;
    10 
    11 int n,m,cnt,sum;
    12 int deg[maxn],G[maxn][maxn];
    13 int x[maxn],y[maxn],id[maxn][maxn];
    14 int d[maxn][maxn][maxn];
    15 int s[5],t[5];
    16 int dx[] = {0,0,0,-1,1};
    17 int dy[] = {0,1,-1,0,0};
    18 
    19 int find_ID(int a,int b,int c){
    20     return (a<<16)|(b<<8)|c;
    21 }
    22 
    23 bool conflict(int a,int b,int a2,int b2){
    24     if((a2==b && a==b2) || a2==b2) return true;
    25     return false;
    26 }
    27 
    28 int bfs(){
    29     queue<int> que;
    30     d[s[0]][s[1]][s[2]] = 0;
    31     que.push(find_ID(s[0],s[1],s[2]));
    32     while(!que.empty()){
    33         int top = que.front();que.pop();
    34         int a = (top>>16)&0xff,b = (top>>8)&0xff,c = (top&0xff);
    35         if(a==t[0] && b==t[1] && c==t[2]) return d[a][b][c];
    36         for(int i = 0;i < deg[a];i++){
    37             int a2 = G[a][i];
    38             for(int j = 0;j < deg[b];j++){
    39                 int b2 = G[b][j];
    40                 if(conflict(a,b,a2,b2)) continue;
    41                 for(int k = 0;k < deg[c];k++){
    42                     int c2 = G[c][k];
    43                     if(d[a2][b2][c2] != -1) continue;
    44                     if(conflict(a,c,a2,c2)) continue;
    45                     if(conflict(b,c,b2,c2)) continue;
    46                     d[a2][b2][c2] = d[a][b][c]+1;
    47                     que.push(find_ID(a2,b2,c2));
    48                 }
    49             }
    50         }
    51     }
    52     return -1;
    53 }
    54 
    55 int main()
    56 {
    57     //freopen("input.txt","r",stdin);
    58     //freopen("output.txt","w",stdout);
    59     while(~scanf("%d%d%d
    ",&m,&n,&sum) && (m||n||sum)){
    60         char gra[maxs][maxs];
    61         cnt = 0;
    62         memset(d,-1,sizeof(d));
    63         for(int i = 0;i < n;i++) fgets(gra[i],maxs,stdin);
    64 
    65         for(int i = 0;i < n;i++){
    66             for(int j = 0;j < m;j++){
    67                 if(gra[i][j] != '#'){
    68                     x[cnt] = i,y[cnt] = j,id[i][j] = cnt;
    69                     if(islower(gra[i][j])) s[gra[i][j]-'a'] = cnt;
    70                     else if(isupper(gra[i][j])) t[gra[i][j]-'A'] = cnt;
    71                     cnt++;
    72                 }
    73             }
    74         }
    75 
    76         for(int i = 0;i < cnt;i++){
    77             int X = x[i],Y = y[i];
    78             deg[i] = 0;
    79             for(int k = 0;k < 5;k++){
    80                 int xx = X+dx[k],yy = Y+dy[k];
    81                 if(gra[xx][yy] != '#') G[i][deg[i]++] = id[xx][yy];
    82             }
    83         }
    84 
    85         if(sum <= 2){
    86             s[2] = t[2] = G[cnt][0] = cnt;
    87             deg[cnt++] = 1;
    88         }
    89         if(sum <= 1){
    90             s[1] = t[1] = G[cnt][0] = cnt;
    91             deg[cnt++] = 1;
    92         }
    93 
    94         printf("%d
    ",bfs());
    95     }
    96     return 0;
    97 }

    再来一个双向BFS,530ms

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <queue>
      6 using namespace std;
      7 
      8 const int maxs = 20;
      9 const int maxn = 150;
     10 
     11 int n,m,cnt,sum;
     12 int deg[maxn],G[maxn][maxn];
     13 int x[maxn],y[maxn],id[maxn][maxn];
     14 int d[maxn][maxn][maxn];
     15 int vis[maxn][maxn][maxn];
     16 int s[5],t[5];
     17 int dx[] = {0,0,0,-1,1};
     18 int dy[] = {0,1,-1,0,0};
     19 
     20 int find_ID(int a,int b,int c){
     21     return (a<<16)|(b<<8)|c;
     22 }
     23 
     24 bool conflict(int a,int b,int a2,int b2){
     25     if((a2==b && a==b2) || a2==b2) return true;
     26     return false;
     27 }
     28 
     29 int bfs(){
     30     queue<int> que,anti_que;
     31     d[s[0]][s[1]][s[2]] = 0;
     32     d[t[0]][t[1]][t[2]] = 0;
     33 
     34     que.push(find_ID(s[0],s[1],s[2]));
     35     anti_que.push(find_ID(t[0],t[1],t[2]));
     36 
     37     vis[s[0]][s[1]][s[2]] = 1;
     38     vis[t[0]][t[1]][t[2]] = 2;
     39 
     40     while(!que.empty() && !anti_que.empty()){
     41         int num = que.size(),anti_num = anti_que.size();
     42         while(num--){
     43             int top = que.front();que.pop();
     44             int a = (top>>16)&0xff,b = (top>>8)&0xff,c = (top&0xff);
     45 
     46             for(int i = 0;i < deg[a];i++){
     47                 int a2 = G[a][i];
     48                 for(int j = 0;j < deg[b];j++){
     49                     int b2 = G[b][j];
     50                     if(conflict(a,b,a2,b2)) continue;
     51                     for(int k = 0;k < deg[c];k++){
     52                         int c2 = G[c][k];
     53                         if(conflict(a,c,a2,c2)) continue;
     54                         if(conflict(b,c,b2,c2)) continue;
     55 
     56                         if(vis[a2][b2][c2] == 0){
     57                             d[a2][b2][c2] = d[a][b][c]+1;
     58                             vis[a2][b2][c2] = 1;
     59                             que.push(find_ID(a2,b2,c2));
     60                         }
     61                         else if(vis[a2][b2][c2] == 2){
     62                             return d[a][b][c]+d[a2][b2][c2]+1;
     63                         }
     64                     }
     65                 }
     66             }
     67         }
     68 
     69         while(anti_num--){
     70             int top = anti_que.front();anti_que.pop();
     71             int a = (top>>16)&0xff,b = (top>>8)&0xff,c = (top&0xff);
     72 
     73             for(int i = 0;i < deg[a];i++){
     74                 int a2 = G[a][i];
     75                 for(int j = 0;j < deg[b];j++){
     76                     int b2 = G[b][j];
     77                     if(conflict(a,b,a2,b2)) continue;
     78                     for(int k = 0;k < deg[c];k++){
     79                         int c2 = G[c][k];
     80                         if(conflict(a,c,a2,c2)) continue;
     81                         if(conflict(b,c,b2,c2)) continue;
     82 
     83                         if(vis[a2][b2][c2] == 0){
     84                             d[a2][b2][c2] = d[a][b][c]+1;
     85                             vis[a2][b2][c2] = 2;
     86                             anti_que.push(find_ID(a2,b2,c2));
     87                         }
     88                         else if(vis[a2][b2][c2] == 1){
     89                             return d[a][b][c]+d[a2][b2][c2]+1;
     90                         }
     91                     }
     92                 }
     93             }
     94         }
     95     }
     96     return -1;
     97 }
     98 
     99 int main()
    100 {
    101     //freopen("input.txt","r",stdin);
    102     //freopen("output.txt","w",stdout);
    103     while(~scanf("%d%d%d
    ",&m,&n,&sum) && (m||n||sum)){
    104         char gra[maxs][maxs];
    105         cnt = 0;
    106         memset(d,-1,sizeof(d));
    107         memset(vis,0,sizeof(vis));
    108         for(int i = 0;i < n;i++) fgets(gra[i],maxs,stdin);
    109 
    110         for(int i = 0;i < n;i++){
    111             for(int j = 0;j < m;j++){
    112                 if(gra[i][j] != '#'){
    113                     x[cnt] = i,y[cnt] = j,id[i][j] = cnt;
    114                     if(islower(gra[i][j])) s[gra[i][j]-'a'] = cnt;
    115                     else if(isupper(gra[i][j])) t[gra[i][j]-'A'] = cnt;
    116                     cnt++;
    117                 }
    118             }
    119         }
    120 
    121         for(int i = 0;i < cnt;i++){
    122             int X = x[i],Y = y[i];
    123             deg[i] = 0;
    124             for(int k = 0;k < 5;k++){
    125                 int xx = X+dx[k],yy = Y+dy[k];
    126                 if(gra[xx][yy] != '#') G[i][deg[i]++] = id[xx][yy];
    127             }
    128         }
    129 
    130         if(sum <= 2){
    131             s[2] = t[2] = G[cnt][0] = cnt;
    132             deg[cnt++] = 1;
    133         }
    134         if(sum <= 1){
    135             s[1] = t[1] = G[cnt][0] = cnt;
    136             deg[cnt++] = 1;
    137         }
    138 
    139         printf("%d
    ",bfs());
    140     }
    141     return 0;
    142 }
  • 相关阅读:
    洛谷P1157----组合数的输出
    NOIP幂次方
    NOIP2012----借教室
    SpringBoot+Spring常用注解总结
    Spring常见问题总结
    Java 命名之道
    Redis 常见问题总结
    关于缓存的一些重要概念(Redis 前置菜)
    MySQL 高性能优化规范建议
    关于数据库中如何存储时间的一点思考
  • 原文地址:https://www.cnblogs.com/npugen/p/9539734.html
Copyright © 2020-2023  润新知