原题链接:https://vjudge.net/problem/UVA-1601
分类:技巧优化
备注:双向广搜,经典题
记录状态很容易做,把每个位置计算一下二维数组转一维即可。
要注意的是不动也是一种状态,因此每个位置有1-5种选择的可能。优化的技巧就是利用’#'数量很多,因此只要记录空白相连的空白即可。
对于n=1和n=2要注意设置一个局外量,使得遍历不被干扰。
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int w,h,n;
int dis[2][260][260][260];
char g[20][20];
inline int cal(int row,int col){
return row * w + col;
}
int st[3],ed[3];
vector<int>e[260];
inline void pushup(int row,int col){
int x = cal(row,col);
for(int i = 0; i < 4; i++){
int row2 = row + dir[i][0];
int col2 = col + dir[i][1];
if(row2 < 0 || col2 < 0 || row2 >= h || col2 >= w)continue;
if(g[row2][col2] == '#')continue;
e[x].push_back(cal(row2,col2));
}
}
struct node{
int pos[3];
node(int a, int b, int c){
pos[0] = a; pos[1] = b; pos[2] = c;
}
};
inline void nxtStp(queue<node>& q, int o, int& ans){
if(q.empty())return;
node u = q.front(); q.pop();
int a = u.pos[0],b = u.pos[1],c = u.pos[2];
if(dis[o^1][a][b][c] != -1){
ans = min(ans,dis[o][a][b][c] + dis[o^1][a][b][c]);
}
for(int i = 0; i < e[a].size(); i++){
int a2 = e[a][i];
for(int j = 0; j < e[b].size(); j++){
int b2 = e[b][j];
if(a2 == b2 || (a2 == b && b2 == a))continue;
for(int k = 0; k < e[c].size(); k++){
int c2 = e[c][k];
if(a2 == c2 || (a2 == c && c2 == a))continue;
if(b2 == c2 || (b2 == c && c2 == b))continue;
if(dis[o][a2][b2][c2] != -1)continue;
dis[o][a2][b2][c2] = dis[o][a][b][c] + 1;
q.push(node(a2,b2,c2));
}
}
}
}
int main(void){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(scanf("%d %d %d", &w, &h, &n) && (w || h || n)){
memset(dis,-1,sizeof(dis));
for(int i = 0; i < 260; i++)e[i].clear(),e[i].push_back(i);
for(int i = 0; i < 3; i++)st[i] = ed[i] = 0;
for(int i = 0; i < h; i++){
getchar();
for(int j = 0; j < w; j++){
scanf("%c",&g[i][j]);
if(islower(g[i][j]))st[g[i][j]-'a'] = cal(i,j);
if(isupper(g[i][j]))ed[g[i][j]-'A'] = cal(i,j);
}
}
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
pushup(i,j);
}
}
if(n<=2)st[2]=ed[2]=257;
if(n==1)st[1]=ed[1]=258;
queue<node>q[2];
q[0].push(node(st[0],st[1],st[2]));
dis[0][st[0]][st[1]][st[2]] = 0;
q[1].push(node(ed[0],ed[1],ed[2]));
dis[1][ed[0]][ed[1]][ed[2]] = 0;
int ans = inf, o = 0 ;
while(!q[0].empty()&&!q[1].empty()){
nxtStp(q[o], o, ans);
o = o^1;
if(ans!=inf)break;
}
printf("%d\n",ans);
}
return 0;
}