/*******************************************************
2017.1.26 --19:50
重新做了一遍这个题目。
其实一个单向的BFS 就可以过 920ms,思路和 原来的差不多,只不过改成了 结构体队列(用数组存的,数组肯定要比STL的queue 要快),里面的x[3] 存的是三只鬼的位置,这个位置xy坐标压缩成了一个整数,这个也是很好想的,xy坐标肯定小于16(最外面肯定是墙), 所以二进制最多4位, 这样二进制一组合,最多只有八位,不会超过256.
因此判重也就简单了, 用vis[256][256][256] 就可以了.
因为墙很多,空格很少,因此可以先给空格标号建立一张表 这样就又快了不少。
详细见代码:
最普通的bfs:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define Siz(x) (int)x.size()
using namespace std;
int n, m, r, g[3], hear, rear;
bool vis[256][256][256];
char s[20][20];
vector<int>G[260];
int id[20][20];
int mp[256];
const int dx[] = {1,-1,0,0,0};
const int dy[] = {0,0,-1,1,0};
bool isal(char& c){return c >= 'A' && c <= 'Z' && c >= 'a' && c <= 'z';}
bool isup(char& c){return c >= 'A' && c <= 'Z';}
bool islow(char& c){return c >= 'a' && c <= 'z';}
struct Node{
int x[3];
int d;
}p[5000000];
int code(int x,int y){ return (x << 4) | (y); }
int decode(int& x,int& y,int z){
y = z % 16;
z/=16;
x = z;
}
int t[3],t2[3];
bool conf(int a,int b,int c,int d){
// printf("%d -> %d , %d -> %d\n",a,b,c,d);
if (b == d) return 1;
if (a == d && b == c) return 1;
return 0;
}
int bfs(){
memset(vis,0,sizeof vis);
vis[p[0].x[0] ][p[0].x[1] ][p[0].x[2] ] = 1;
hear = 0, rear = 1;
while(hear < rear){
Node u = p[hear++];
// for (int i = 0; i < 3; ++i) printf("%d ",u.x[i]);
// puts("");
// for (int i = 0; i < 3; ++i) printf("%d ",g[i]);
// puts("");
if (u.x[0] == g[0] && u.x[1] == g[1] && u.x[2] == g[2]) return u.d;
for (int i = 0; i < Siz(G[u.x[0]]); ++i){
int v0 = G[u.x[0] ][i];
for (int j = 0; j < Siz(G[u.x[1]] ); ++j){
int v1 = G[u.x[1] ][j];
if (conf(u.x[0],v0,u.x[1],v1))continue;
for (int k = 0; k < Siz(G[u.x[2] ]); ++k){
int v2 = G[u.x[2] ][k];
// printf("%d\n",v2);
// printf("%d %d %d\n",v0,v1,v2);
if (conf(u.x[0],v0,u.x[2],v2) || conf(u.x[1],v1,u.x[2],v2))continue;
if (!vis[v0][v1][v2]){
vis[v0][v1][v2] = 1;
p[rear].x[0] = v0;
p[rear].x[1] = v1;
p[rear].x[2] = v2;
p[rear].d = u.d + 1;
rear++;
}
}
}
}
}
return -1;
}
int main() {
while(~scanf("%d%d%d%*c",&m,&n,&r) && (n || m || r)){
memset(p,0,sizeof p);
for (int i = 0; i < 260; ++i){
G[i].clear();
}
for (int i = 0; i < n; ++i){
fgets(s[i],20,stdin);
}
int cnt=0;
for (int i = 0; i < n; ++i){
for (int j = 0; j < m; ++j){
if (s[i][j] != '#'){
id[i][j] = cnt++;
mp[cnt-1] = code(i,j);
if (islow(s[i][j])){
p[0].x[s[i][j] -'a' ] = cnt-1;
}
else if (isup(s[i][j])){
g[s[i][j]-'A' ] = cnt-1;
}
}
}
}
for (int i = 0; i < cnt; ++i){
int x,y;
decode(x,y,mp[i]);
for (int j = 0; j < 5; ++j){
int xx = dx[j] + x;
int yy = dy[j] + y;
if (xx < n && xx >= 0 && yy < m && yy >= 0 && s[xx][yy] != '#'){
G[i].push_back(id[xx][yy]);
}
}
}
// for (int i = 0; i < cnt; ++i){
// printf("%d:",i);
// for (int j = 0; j < Siz(G[i]); ++j){
// printf("%d ",G[i][j]);
//
//
// }
// puts("");
//
//
// }
if (r == 1){
G[cnt].push_back(cnt);
p[0].x[1] = cnt;
g[1] = cnt++;
G[cnt].push_back(cnt);
p[0].x[2] = cnt;
g[2] = cnt++;
}
else if (r == 2){
G[cnt].push_back(cnt);
p[0].x[2] = cnt;
g[2] = cnt;
cnt++;
}
// printf("%d\n",G[7][0]);
// for (int i = 0; i < 3; ++i)printf("%d ",g[i]);
printf("%d\n",bfs());
}
return 0;
}
/*
5 5 2
#####
#A#B#
# #
#b#a#
#####
*/
/******************************************************
大体题意:
你给一个h*w 的网格,网格上最多有三只小鬼,小鬼用小写字母abc 表示,他们的目标用ABC表示,问小鬼移动到目标最短的步数,他们可以同时走,走法有五种:上下左右和不动,其中有几种情况的走法是非法的:
1.两只小鬼一步以内交换了位置。
2.两只小鬼的下一步是同一个位置。
其余情况合法!
思路:
先将不是#的位置变成标号。
然后把所有空格提出来建立一张图,把初始位置的鬼存到s数组中,把鬼的目标位置存到t数组中。
然后以每个空格为中心 建立一张图G数组
然后把不够3个鬼的样例情况变成3个鬼。
然后开始双向bfs,正着走 vis 标记为1 反着走 标记为2
然后不断记录dis 走过的距离, 当正着走发现标记为2时返回dist 和
当反着走发现标记为1 时,返回dis和
说明一下 判断是否情况合法的函数:
bool config(int a,int b,int a2,int b2){
return a2 == b2 || (a==b2 && b == a2);
}
四个参数 鬼1 的初始位置 鬼2 的初始位置 鬼1 的下一步位置 鬼2 的下一步位置。
当a2 == b2 也就是下一步走到同一个位置了 非法!
当(a==b2 && b == a2); 也就是一步以内交换位置了 非法!
int ID(int a,int b,int c){
return (a<<16) | (b<<8) | c;
}
这个是对三个数进行编码 省了不少空间!
很极限的 代码 在POJ 真的就差一点点就爆内存了!
具体在看代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define cin freopen("cin.txt","r",stdin);
using namespace std;
int w,h,n;
const int maxn = 200 + 1;
char mp[20][20];
int deg[maxn];
int dis[maxn][maxn][maxn];
int vis[maxn][maxn][maxn];
int s[3],t[3],G[maxn][5];
const int dx[] = {1,-1,0,0,0};
const int dy[] = {0,0,1,-1,0};
queue<int >qb,qf;
int ID(int a,int b,int c){
return (a<<16) | (b<<8) | c;
}
bool config(int a,int b,int a2,int b2){
return a2 == b2 || (a==b2 && b == a2);
}
bool init(int x,int y){
return x >= 0 && x < h && y >= 0 && y < w;
}
int bfs(){
memset(dis,0,sizeof dis);
memset(vis,0,sizeof vis);
while(!qb.empty())qb.pop();
while(!qf.empty())qf.pop();
vis[s[0]][s[1]][s[2]] = 1;
vis[t[0]][t[1]][t[2]] = 2;
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]));
while(!qb.empty() || !qf.empty()){
int bnum = qb.size(),fnum = qf.size();
while(!qb.empty()){
int u = qb.front(); qb.pop();
int a=(u>>16)&255,b=(u>>8)&255,c=u&255;
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 (config(a,b,a2,b2))continue;
for (int k = 0; k < deg[c]; ++k){
int c2 = G[c][k];
if (config(a,c,a2,c2) || config(b,c,b2,c2))continue;
if (vis[a2][b2][c2] == 0){
vis[a2][b2][c2] = 2;
dis[a2][b2][c2] = dis[a][b][c] + 1;
qb.push(ID(a2,b2,c2));
}
else if (vis[a2][b2][c2] == 1){
return dis[a2][b2][c2] + dis[a][b][c];
}
}
}
}
}
while(!qf.empty()){
int u = qf.front(); qf.pop();
int a=(u>>16)&255,b=(u>>8)&255,c=u&255;
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 (config(a,b,a2,b2))continue;
for (int k = 0; k < deg[c]; ++k){
int c2 = G[c][k];
if (config(a,c,a2,c2) || config(b,c,b2,c2))continue;
if (vis[a2][b2][c2] == 0){
vis[a2][b2][c2] = 1;
dis[a2][b2][c2] = dis[a][b][c] + 1;
qf.push(ID(a2,b2,c2));
}
else if (vis[a2][b2][c2] == 2){
return dis[a2][b2][c2] + dis[a][b][c];
}
}
}
}
}
}
}
int main(){
// cin;
while(scanf("%d%d%d",&w,&h,&n) == 3 && (w||h||n)){
gets(mp[0]);
for (int i = 0; i < h; ++i)gets(mp[i]);
int cnt = 0,x[maxn],y[maxn],id[maxn][maxn];
for (int i = 0; i < h; ++i){
for (int j = 0; j < w; ++j){
if (mp[i][j] != '#'){
x[cnt] = i;
y[cnt] = j;
id[i][j] = cnt;
char ch = mp[i][j];
if (islower(ch))s[ch-'a'] = cnt;
if (isupper(ch))t[ch-'A'] = cnt;
cnt++;
}
}
}
for (int i = 0; i < cnt; ++i){
deg[i] = 0;
for (int j = 0; j < 5; ++j){
int xx = x[i] + dx[j];
int yy = y[i] + dy[j];
if (init(xx,yy) && mp[xx][yy] != '#')G[i][deg[i]++] = id[xx][yy];
}
}
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++;
}
if (s[0] == t[0] && s[1] == t[1] && s[2] == t[2])printf("0\n");
else printf("%d\n",bfs());
}
return 0;
}