这题可以用普通bfs来做 也可以用双向bfs来做(先欠着)
有点类似专题训练的一题 不过那题是找钥匙开门 不过都用了状态压缩
题意: n,m(<=16) 的网络上有t(<=3)小写字母 并且网络上有其大写字母 要求最少的步使得所有小写字母到大写字母里面去 每步可以多个小写字母同时移动(上下左右加不动) 移动后任意两个小写字母不能占用同一个位置 也不能在一步之内进行交换位置
且任何一个2*2子网络中至少有一个障碍格
分析: 小写字母最多三个 已经算是少的了 但是有十六乘十六网络 当有三个小写字母的时候 状态总数为 256的三次方 每次状态转移有 5的三次方枚举量 普通bfs肯定是超时的
题目已经暗示了大部分格子都是障碍 因此应该把所有的状态列出来 形成一张图 而不是临时判断五种方案是否合理
过程:先是给所有有效格标号 储存 然后枚举所有的状态 (我现在还是不懂这有什么区别 一个是在main里面判断地图 一个是在bfs里面判断地图 总的枚举量也没有减少?)
然后状态压缩就十分巧妙了 因为格子最多标号为 十六乘十六等于二百五十六 为0xff 为2的八次方 所以左移八位 要得到改状态时右移 取&0xff
还有就是当字母不满三个的时候 加至三个 方便处理 因为状态压缩的相关都是以三个为基准的
看到bfs先判断枚举量 因为这种bfs和我之前做的普通bfs不同 标记数组状态很多 所以要谨慎
#include<bits/stdc++.h> using namespace std; #define N 150 int dis[N]; int n,m,t; char mp[N][N]; int id[N][N]; int x[N]; int y[N]; int s[4]; int e[4]; int G[N][N]; int vis[N][N][N]; int dx[5]={0,0,0,1,-1}; int dy[5]={0,1,-1,0,0}; bool judge(int x,int x1,int y,int y1) { if(x1==y1||(x==y1&&x1==y) ) return 0; return 1; } int id1(int a,int b,int c) { return (a<<16)|(b<<8)|c; } bool inmap(int x,int y) { if(x>=1&&x<=n&&y>=1&&y<=m) return 1; return 0; } int bfs() { memset(vis,-1,sizeof( vis)); queue<int>q; q.push( id1(s[0],s[1],s[2]) ); vis[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; printf("%d %d %d ",a,b,c); if(a==e[0]&&b==e[1]&&c==e[2])return vis[a][b][c]; for(int i=0;i<dis[a];i++) { int a2=G[a][i]; for(int j=0;j<dis[b];j++) { int b2=G[b][j]; if(!judge(a,a2,b,b2))continue; for(int k=0;k<dis[c];k++) { int c2=G[c][k]; if(!judge(a,a2,c,c2))continue; if(!judge(b,b2,c,c2))continue; if(vis[a2][b2][c2]!=-1)continue; vis[a2][b2][c2]=vis[a][b][c]+1; q.push( id1(a2,b2,c2) ); } } } } return -1; } int main() { while(scanf("%d%d%d",&m,&n,&t)&&t) { getchar(); for(int i=0;i<n;i++) fgets(mp[i],100,stdin); int cnt=0;int goal=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(mp[i][j]!='#') { id[i][j]=cnt; x[cnt]=i;y[cnt]=j; if(islower(mp[i][j])){s[ mp[i][j]-'a' ]=cnt; } if(isupper(mp[i][j])){e[ mp[i][j]-'A' ]=cnt; } cnt++; } printf("%d %d %d ",s[0],s[1],s[2]); printf("%d %d %d ",e[0],e[1],e[2]); for(int i=0;i<cnt;i++) { dis[i]=0; for(int k=0;k<5;k++) { int nx=x[i]+dx[k]; int ny=y[i]+dy[k]; if(inmap(nx,ny)&&mp[nx][ny]!='#')G[i][dis[i]++ ]=id[nx][ny]; } } if(t<=2){dis[cnt]=1;G[cnt][0]=cnt;s[2]=e[2]=cnt++;} if(t<=1){dis[cnt]=1;G[cnt][0]=cnt;s[1]=e[1]=cnt++;} printf("%d ",bfs()); } return 0; }