题目链接:
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