题目:
既然是状态压缩,那就在这里说一下状态压缩:
题上有A~J个门,有a~j个钥匙,还有终点,我们用二进制的方式来标记。
从a~j一共有十位,那我们就需要十个二进制位。
标 记:a b c d e f g h i j
第几位:0 0 0 0 0 0 0 0 0 0
位编号:1 2 3 4 5 6 7 8 9 10
我们通过改变每一位的0和1来标记我当前拥有的钥匙的可能,也就是状态压缩,用vis[x][y][key]来表示当前在x,y点的状态。当遇到铁门时,先用|运算判断key的值1<<(map[x][y]-'A')的值和原来的key值是否一样,如果一样就代表当前有钥匙可以打开这个门,可以继续走,反之不能走这个门,因为没有钥匙。
如果遇到钥匙的话就更新key的值,然后在把当前状态标记为1,进行正常的广搜就可以,具体看注释
(关于位运算可以看一下搜狗百科的关键字:位运算)
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 10000007
#define debug() puts("what the fuck!!!")
#define N 1001000
#define M 1000000
#define ll long long
using namespace std;
int n,m,ans,t,sx,sy,ex,ey;
char map[25][25];
int vis[25][25][(1<<10)+20];//用二进制位来记录状态
int go[4][2]= {0,1,0,-1,1,0,-1,0};
struct node
{
int x,y,step;
int key;
};
int bfs(int x,int y)
{
node now,to;
now.x=x,now.y=y,now.step=0,now.key=0;
vis[x][y][0]=1;
queueq;
q.push(now);
while(!q.empty())
{
now=q.front();
q.pop();
if(now.x==ex&&now.y==ey&&now.step=0&&to.x=0&&to.y='A'&&map[to.x][to.y]<='J')
{
int key=to.key|(1<<(map[to.x][to.y]-'A'));//看看会不会对应位置的二进制数造成影响,从而判断有没有打开这扇门的钥匙
if(key!=to.key)//造成影响证明没有钥匙,直接进行下一层循环
continue;
}
if(map[to.x][to.y]>='a'&&map[to.x][to.y]<='j')
{
to.key=to.key|(1<<(map[to.x][to.y]-'a'));//把当前的钥匙吸收进去
}
vis[to.x][to.y][to.key]=1;
q.push(to);
}
}
}
return -1;
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&t))
{
mem(map,0);
mem(vis,0);
for(int i=0; i