状压BFS
题意:1个机器人找几个垃圾,求出最短路径。
状压BFS,这道题不能用普通BFS二维vis标记数组去标记走过的路径,因为这题是可以往回走的,而且你也不能只记录垃圾的数量就可以了,因为它有可能重复走同一个垃圾。其实解决的办法就是把vis标记数组开到3维,用来存每次走的状态。再通过位运算即可。
下面是2中常见的位运算操作:
1、加入某一个垃圾:rubblish | =( 1 << i );
eg: 0001 | 0100 =0101 ;
2、进行垃圾匹配 :if( ( rubblish & ( 1 << i ) ) = = 0 ) continue;(注意括号的位置)
eg: 0010 &1001=0 不匹配;
0010 & 1011=1;可以匹配。
谨记:以后像这种找垃圾、找钥匙去开门、可以跨越障碍求最短路径等等的题目,就可以考虑用状压BFS。(一般这些垃圾。钥匙不会超过10个,因为那样三维数组存不下)
还有这题也可以用TSP去解。
1 #include<stdio.h> 2 #include<string.h> 3 #define INF 0x3f3f3f3f 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 bool vis[21][21][1<<10];//vis数组存的是垃圾的状态 8 char g[21][21]; 9 int key[21][21];//垃圾种类 10 int ans=INF; 11 int n,m,sx,sy; 12 int dx[]={1,0,-1,0},dy[]={0,1,0,-1}; 13 int C; 14 struct mask 15 { 16 int x,y,key,step; 17 mask(int x,int y,int key,int step):x(x),y(y),key(key),step(step){}; 18 }; 19 bool check(int a,int b){return 0<=a&&a<m&&0<=b&&b<n;} 20 //判断是否找到所有的垃圾 21 bool OK(int mask) 22 { 23 for(int i=0;i<C;i++) 24 { 25 if(mask&1<<i); 26 else return false; 27 } 28 return true; 29 } 30 int bfs() 31 { 32 queue<mask>q; 33 while(q.size())q.pop(); 34 q.push(mask(sx,sy,0,0)); 35 memset(vis,false,sizeof(vis)); 36 vis[sx][sy][0]=true; 37 while(q.size()){ 38 mask tmp=q.front();q.pop(); 39 if(OK(tmp.key)) 40 { 41 ans=min(ans,tmp.step); 42 } 43 for(int i=0;i<4;i++) 44 { 45 int nx=tmp.x+dx[i]; 46 int ny=tmp.y+dy[i]; 47 int nkey=tmp.key; 48 if(g[nx][ny]!='x'&&check(nx,ny)&&!vis[nx][ny][nkey]) 49 { 50 if(g[nx][ny]=='*') 51 { 52 nkey|=key[nx][ny]; 53 } 54 vis[nx][ny][nkey]=true; 55 q.push(mask(nx,ny,nkey,tmp.step+1)); 56 } 57 } 58 } 59 return ans==INF?-1:ans; 60 } 61 int main() 62 { 63 while(~scanf("%d %d",&n,&m)){ 64 if(n==0&&m==0)break; 65 C=0; 66 ans=INF; 67 memset(key,0,sizeof(key)); 68 for(int i=0;i<m;i++) 69 { 70 scanf("%s",g[i]); 71 for(int j=0;j<n;j++) 72 { 73 if(g[i][j]=='o') 74 { 75 sx=i; 76 sy=j; 77 } 78 if(g[i][j]=='*') 79 { 80 key[i][j]=1<<C++;//预处理,把要清理的垃圾存入key数组中,即把第C个垃圾加入到key中 81 } 82 } 83 } 84 printf("%d\n",bfs()); 85 } 86 }