借鉴了这位大神的代码理解的:有一种力量叫乐观,
状态压缩就是用二进制表示状态
在搜索中有很多种状态,手中有0把钥匙,有1把钥匙,有2把钥匙......
题目中是A-J一共有10把钥匙,
有钥匙和没有钥匙一共两种情况
一共十把所以有pow(2,10)种情况也就是1024。
1024转为二进制就是1 00000 00000。
开成数组正好是0-1023 对应的二进制就是0-1111111111
有A钥匙的时候就是0000000001 ‘A’-'A'=0;1<<0=1;转为二进制就是1
有B钥匙的时候就是0000000010 'B'-'A'=1;1<<1=2; 转为2进制就是10
有C钥匙的时候就是0000000100 'C'-'A'=2;1<<2=4; 转为2进制就是100
但是当手里有手里有钥匙的时候又捡到一把该怎么办:
例如有A钥匙的时候捡到一把B钥匙:
0000000001|0000000010=0000000011;
开锁的时候:
遇到一扇B门,你手里只有一把A钥匙和C钥匙怎么判断开门:
'B'-'A'=1;
1<<1=2;
B门表示为0000000010
手里有一把A钥匙和C钥匙用二进制表示为0000000101
0000000010&0000000101=0 说明不能开门。
因为若有B钥匙结果必定不为0。
所以把数组开成三维的,第三维就是为状态开的
你在搜索中标记已经搜索过的,就和普通BFS一样。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include"queue"
using namespace std;
const int maxn=50;
char g[maxn][maxn];
int visit[maxn][maxn][(1<<10)+20];
int r,c,t;
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
struct point{
int x,y,step,key;
point()
{
x=y=step=key=0;
}
}Start,End;
bool check(int x,int y)
{
return x>=0&&x<r&&y>=0&&y<c;
}
int bfs()
{
queue<point>dot;
dot.push(Start);
visit[Start.x][Start.y][Start.key]=1;
while(!dot.empty())
{
point cur=dot.front();
dot.pop();
point next;
for(int i=0;i<4;i++)
{
next.key=cur.key;
next.x=cur.x+dir[i][0];
next.y=cur.y+dir[i][1];
if(check(next.x,next.y)&&g[next.x][next.y]!='*'&&!visit[next.x][next.y][next.key])
{
if(g[next.x][next.y]=='^')
{
next.step=cur.step+1;
return next.step;
}
else if(g[next.x][next.y]>='a'&&g[next.x][next.y]<='j')
{
next.key=next.key|(1<<(g[next.x][next.y]-'a'));//改变标志
visit[next.x][next.y][next.key]=1;
next.step=cur.step+1;
dot.push(next);
}
else if(g[next.x][next.y]>='A'&&g[next.x][next.y]<='J')
{
if((1<<(g[next.x][next.y]-'A'))&next.key) //表示能开锁
{
visit[next.x][next.y][next.key]=1;
next.step=cur.step+1;
dot.push(next);
}
}
else if(g[next.x][next.y]=='.'||g[next.x][next.y]=='@')
{
visit[next.x][next.y][next.key]=1;
next.step=cur.step+1;
dot.push(next);
}
}
}
}
return -1;
}
int main()
{
//freopen("a.txt","r",stdin);
while(scanf("%d%d%d",&r,&c,&t)!=EOF)
{
//cout<<"t:"<<t<<endl;
memset(visit,0,sizeof(visit));
for(int i=0;i<r;i++)
scanf("%s",g[i]);
for(int i=0;i<r;i++)
for(int j=0;j<c;j++)
if(g[i][j]=='@')
{
Start.x=i;Start.y=j;
}
else if(g[i][j]=='^')
{
End.x=i;End.y=j;
}
if(abs(End.x-Start.x)+abs(End.y-Start.y)>t) {printf("%d\n",-1);continue;}
int ans=bfs();
//cout<<"ans:"<<ans<<endl;
if(ans>0&&ans<t)
printf("%d\n",ans);
else
printf("%d\n",-1);
}
return 0;
}