http://acm.hdu.edu.cn/showproblem.php?pid=1429
几组测试数据:
4 5 17
@A.B.
a*.*.
*..*^
c..b*
4 5 111
@A.B.
.*.*.
.*.*^
cC.b*
1 4 11
@cC^
1 8 11
@abACcB^
2 8 111
@AABBCD^
a*b*cBd*
6 7 111
@aAbBC*
AAA.BC*
BBBBcC*
CCCCCC*
.******
......^
状态压缩就是用二进制表示状态
在搜索中有很多种状态,手中有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。
————————————————
参考:https://blog.youkuaiyun.com/qq_32454729/article/details/52087216
所以这里的还有一个点就是vis要开三维,第三维表示当前拥有的钥匙状态量,如果在当前状态走过的点则不能再走,拿都钥匙后可以重新回去。这个看原来的第一个测试数据就能看出来。 先要下去拿钥匙再回去,所以在模板上更改。第三维的大小看2进制有多少种情况来定
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
//时间限制 状态压缩 在一定条件下可以回路
//每一个结构体的now都有next对应
int vis[24][24][1026];
char ditu[25][25];
int sx,sy,fx,fy;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
struct node{
int x;
int y;
int key;
int output;
};
int n,m,t;
int k;
int bfs()
{
queue<node> que;
node now,next;
now.x=sx,now.y=sy,now.key=0;now.output=0;
que.push(now);
vis[sx][sy][0]=1;
while(que.size())
{
now=que.front();que.pop();
if(now.x==fx&&now.y==fy)
{
return now.output; ///为了方便进行考虑达不到终点的情况,对这里进行模板上的一点修改
}
for(int i=0;i<4;i++)
{
int nx=now.x+dx[i];int ny=now.y+dy[i];int nkey=now.key;int nouput=now.output;
if(nx>=0&&nx<n&&ny>=0&&ny<m&&ditu[nx][ny]!='*'&&vis[nx][ny][nkey]==-1)
{
next.x=nx;next.y=ny;next.key=nkey;next.output=nouput+1;
//vis的第三维的意思是在目前的状态钥匙下是否走过该点,如果走过就不能再走,如果拿到钥匙刷新成下一个状态,就能走
if(ditu[nx][ny]>='a'&&ditu[nx][ny]<='j') //增加钥匙
{
int temp=ditu[nx][ny]-'a';
next.key=(nkey|(1<<temp) );
}
if(ditu[nx][ny]>='A'&&ditu[nx][ny]<='J')
{
int temp=ditu[nx][ny]-'A';
if( (nkey&(1<<temp) )==0) 注意括号!!!!
continue;
}
vis[nx][ny][next.key]=1;
que.push(next);
}
}
}
///注意不能到的情况
return -1;
}
int main(void)
{
while(scanf("%d%d%d",&n,&m,&t)!=EOF)
{
memset(ditu,'\0',sizeof(ditu));memset(vis,-1,sizeof(vis));
for(int i=0;i<n;i++)
cin>>ditu[i];
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(ditu[i][j]=='@')
sx=i,sy=j;
if(ditu[i][j]=='^')
fx=i,fy=j;
}
}
int res=bfs();
if(res>=t)
printf("-1\n");
else if(res<t)
printf("%d\n",res);
}
return 0;
}