状压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 }
View Code

 

posted @ 2018-05-05 22:09  better46  阅读(240)  评论(0编辑  收藏  举报