紫书搜索 例题7-9 UVA - 1601 The Morning after Halloween 双向bfs

题目链接:

https://vjudge.net/problem/UVA-1601

题意:

题解:

http://blog.csdn.net/qq_29169749/article/details/51420097
隐式图搜索问题,类似dijkstra,用bfs解决,这个是单向搜索,弊端是有时候随着搜索的深入,可扩展的结点会越来越多,造成效率变慢,用双向bfs可以解决这个问题

代码:

双向bfs:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
//
const int maxn = 1e5+10;

int w, h, n, s[3], t[3];
char dataset[20][20];
int G[200][5], color[200][200][200], dis[200][200][200];
int deg[200];

int dx[] = {0,0,0,1,-1};
int dy[] = {0,1,-1,0,0};

int ID(int a,int b,int c){
    return (a<<16) | (b<<8) | c;
}

bool conflict(int a,int b,int a2,int b2){
    return a2==b2 || (a==b2 && b==a2);
}

int bfs(){
    queue<int> qf;
    queue<int> qb;
    dis[s[0]][s[1]][s[2]] = 0;
    dis[t[0]][t[1]][t[2]] = 1;
    qf.push(ID(s[0],s[1],s[2]));
    qb.push(ID(t[0],t[1],t[2]));
    color[s[0]][s[1]][s[2]] = 1;
    color[t[0]][t[1]][t[2]] = 2;

    while(!qf.empty() || !qb.empty()){
        int fnum = qf.size(), bnum = qb.size();  //一层一层的拓展。而不是一个点
        while(fnum--){ 
            int u = qf.front(); qf.pop();
            int a = (u>>16)&0xff, b = (u>>8)&0xff, c = u&0xff; //解码出出列状态三个小鬼的位置

            for(int i=0; i<deg[a]; i++){
                int a2 = G[a][i];
                for(int j=0; j<deg[b]; j++){
                    int b2 = G[b][j];
                    if(conflict(a,b,a2,b2)) continue;
                    for(int k=0; k<deg[c]; k++){
                        int c2 = G[c][k];
                        if(conflict(a,c,a2,c2)) continue;
                        if(conflict(b,c,b2,c2)) continue;

                        // if(dis[a2][b2][c2] != -1) continue;  // 不能再这样判断是否访问过了,因为是双向
                        if(color[a2][b2][c2] == 0){
                            color[a2][b2][c2] = 1;
                            dis[a2][b2][c2] = dis[a][b][c]+1;
                            qf.push(ID(a2,b2,c2));
                        }else if(color[a2][b2][c2] == 2){
                            return dis[a][b][c] + dis[a2][b2][c2];  // 这就是为啥最开始的终点初始为1步;
                        }
                    }
                }
            }
        }

        while(bnum--){
            int u = qb.front(); qb.pop();
            int a = (u>>16)&0xff, b = (u>>8)&0xff, c = u&0xff;

            for(int i=0; i<deg[a]; i++){
                int a2 = G[a][i];
                for(int j=0; j<deg[b]; j++){
                    int b2 = G[b][j];
                    if(conflict(a,b,a2,b2)) continue;
                    for(int k=0; k<deg[c]; k++){
                        int c2 = G[c][k];
                        if(conflict(a,c,a2,c2)) continue;
                        if(conflict(b,c,b2,c2)) continue;

                        // if(dis[a2][b2][c2] != -1) continue; 
                        if(color[a2][b2][c2] == 0){
                            color[a2][b2][c2] = 2;
                            dis[a2][b2][c2] = dis[a][b][c] + 1;
                            qb.push(ID(a2,b2,c2));
                        }else if(color[a2][b2][c2] == 1){
                            return dis[a][b][c] + dis[a2][b2][c2];
                        }
                    }
                }
            }
        }
    }

    return -1;
}

int main(){
    while(scanf("%d%d%d\n",&w,&h,&n)==3 && (w+h+n)){
        for(int i=0; i<h; i++) gets(dataset[i]);
        int cnt=0,x[200],y[200],id[20][20];
        for(int i=0; i<h; i++)
            for(int j=0; j<w; j++){
                if(dataset[i][j]!='#'){
                    x[cnt]=i,y[cnt]=j,id[i][j] = cnt;  // cnt表示有多少个空白块
                    if(islower(dataset[i][j])) s[dataset[i][j]-'a'] = cnt;
                    if(isupper(dataset[i][j])) t[dataset[i][j]-'A'] = cnt; 
                    cnt++;
                }
            }

        for(int i=0; i<cnt; i++){ // 用空白块建图
            deg[i] = 0;  // i这个白块周围有多少的白块,就是连线嘛
            for(int j=0; j<5; j++){
                int tx=x[i]+dx[j], ty=y[i]+dy[j];
                if(dataset[tx][ty] != '#') G[i][deg[i]++] = id[tx][ty];
            }
        }

        if(n <= 2) { deg[cnt]=1; G[cnt][0]=cnt; s[2]=t[2]=cnt; cnt++;}
        if(n <= 1) { deg[cnt]=1; G[cnt][0]=cnt; s[1]=t[1]=cnt; cnt++;}

        memset(dis,-1,sizeof(dis));
        memset(color,0,sizeof(color));

        printf("%d\n",bfs());

    }

    return 0;
}

单向bfs:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
//////////////////////////////////////////////////////////////////////////
const int maxn = 1e5+10;

int w,h,n;
int G[200][5],dis[200][200][200],deg[200],s[3],t[3];
char dataset[20][20];
int dx[] = {0,0,0,1,-1};
int dy[] = {0,1,-1,0,0};

inline int ID(int a,int b,int c){
    return (a<<16) | (b<<8) | c;
}

bool conflict(int a,int b,int a2,int b2){
    return (a2==b2) || (a==b2 && b==a2);
}

int bfs(){
    queue<int> q;
    q.push(ID(s[0],s[1],s[2]));
    dis[s[0]][s[1]][s[2]] = 0;
    while(!q.empty()){
        int u = q.front(); q.pop();
        int a = (u>>16)&0xff, b = (u>>8)&0xff, c = u & 0xff;
        if(a==t[0] && b==t[1] && c==t[2]) return dis[a][b][c];

        for(int i=0; i<deg[a]; i++){
            int a2 = G[a][i];
            for(int j=0; j<deg[b]; j++){
                int b2 = G[b][j];
                if(conflict(a,b,a2,b2)) continue;
                for(int k=0; k<deg[c]; k++){
                    int c2 = G[c][k];
                    if(conflict(a,c,a2,c2)) continue;
                    if(conflict(b,c,b2,c2)) continue;

                    if(dis[a2][b2][c2]!=-1) continue;
                    dis[a2][b2][c2] = dis[a][b][c] + 1;
                    q.push(ID(a2,b2,c2)); 
                }
            }
        }
    }
    return -1;
}

int main(){
    while(~scanf("%d%d%d\n",&w,&h,&n) && n){
        for(int i=0; i<h; i++) gets(dataset[i]);

        // for(int i = 0; i < h; i++)  fgets(dataset[i], 20, stdin);

        int cnt=0,x[200],y[200],id[20][20];
        for(int i=0; i<h; i++)
            for(int j=0; j<w; j++){
                if(dataset[i][j] != '#'){
                    x[cnt]=i,y[cnt]=j,id[i][j]=cnt;
                    if(islower(dataset[i][j])) s[dataset[i][j]-'a'] = cnt;
                    else if(isupper(dataset[i][j])) t[dataset[i][j]-'A'] = cnt;
                    cnt++;
                }
            }

        for(int i=0; i<cnt; i++){
            deg[i] = 0;
            for(int j=0; j<5; j++){
                int tx=x[i]+dx[j], ty=y[i]+dy[j];
                if(dataset[tx][ty]!='#') G[i][deg[i]++] = id[tx][ty];
            }
        }
        if(n<=2) { deg[cnt]=1; G[cnt][0]=cnt; s[2]=t[2]=cnt; cnt++;}
        if(n<=1) { deg[cnt]=1; G[cnt][0]=cnt; s[1]=t[1]=cnt; cnt++;}

        memset(dis,-1,sizeof(dis));

        printf("%d\n",bfs());
    }

    return 0;
}
5 5 2
#####
#A#B#
#   #
#b#a#
#####
16 4 3
################
## ########## ##
#    ABCcba    #
################
0 0 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值