紫书搜索 例题7-9 UVA

来源:互联网 发布:将军乃有宇宙之号乎 编辑:程序博客网 时间:2024/03/29 09:38

题目链接:

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_backconst 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_backconst 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
0 0