一个简单的搜索题了
不过有钥匙开门什么的其他条件
(好吧这都不是重点
这题一般的做法应该是状态压缩
就是用一个小于1024的整数的二进制的位来表示当前持有的钥匙
然后检查当前位置的那个数组(我这里叫che
的第三维也开到1024
这样的话每个持有钥匙的状态都对应了这个数组的某一层
其他的就是位运算了
以下是代码
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool che[25][25][1024];
char arr[25][25];
int key[10];
int dor[10];
int n,m,t;
struct state{
int x;
int y;
int time;
int tk;
bool can(int k){
x+=dir[k][0];
y+=dir[k][1];
time++;
if(time>=t)
return false;
if(x<0 || x>=n || y<0 || y>=m || arr[x][y]=='*')
return false;
if(che[x][y][tk])
return false;
if('A'<=arr[x][y] && arr[x][y]<='J')
if((tk|dor[arr[x][y]-'A'])!=key[10]){
return false;
}
if('a'<=arr[x][y] && arr[x][y]<='j')
tk=tk|key[arr[x][y]-'a'];
che[x][y][tk]=true;
return true;
}
};
void fnd(state &p){
for(p.x=0;p.x<n;p.x++)
for(p.y=0;p.y<m;p.y++)
if(arr[p.x][p.y]=='@')
return;
}
int dfs(){
state s;
fnd(s);
s.time=0;
s.tk=0;
queue<state> q;
q.push(s);
while(q.empty()==false){
s=q.front();
if(arr[s.x][s.y]=='^')
return s.time;
for(int i=0;i<4;i++){
s=q.front();
if(s.can(i))
q.push(s);
}
q.pop();
}
return -1;
}
int main(){
key[0]=1;
for(int i=1;i<=10;i++)
key[i]=key[i-1]*2;
key[10]--;
for(int i=0;i<10;i++)
dor[i]=key[10]-key[i];
// #define DEBUG
#ifdef DEBUG
for(int i=0;i<=10;i++)
printf(i<10?"%d ":"%d\n",key[i]);
for(int i=0;i<=9;i++)
printf(i<9?"%d ":"%d\n",dor[i]);
#endif // DEBUG
while(~scanf("%d %d %d",&n,&m,&t)){
for(int i=0;i<n;i++)
scanf("%s",arr[i]);
memset(che,0,sizeof(che));
printf("%d\n",dfs());
}
return 0;
}
其实吧,这不是我第一次的想法
刚开始就觉得没有必要开到1024这么多
优化过之后只要开到11就好了(算了我还是直接说方法好了
这是从o(2^n)到o(n)的优化(虽然只是空间复杂度)
和上一份代码不同
这里的钥匙用一个bool数组表示
为真说明你带了这把钥匙
这里che数组的每一层都唯一对应着一个钥匙
那么che[x][y][k]为TRUE代表的含义是在(x,y)这个位置你带着第k把钥匙来过了
那么如果你身上的钥匙如果不增加的话,这个地方就不值得来了
大体就是这样
每次移动的时候检查这个che数组的每一层
如果你有对应的钥匙而且有你没去过的,那么可以走
不然你都带着钥匙来过了,就不用再来了
还有要注意的是刚出发的时候你没有钥匙
所以要另外设置一个虚拟钥匙(否则你刚出来就动不了了
(想一想,为什么
以上
-----------------------------------------------我是代码的分界线----------------------
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool che[25][25][11];
char arr[25][25];
int dor[10];
int n,m,t;
struct state{
int x;
int y;
int time;
bool key[11];
bool can(int k){
x+=dir[k][0];
y+=dir[k][1];
time++;
if(time>=t)
return false;
if(x<0 || x>=n || y<0 || y>=m || arr[x][y]=='*')
return false;
bool flag=true;
for(int i=0;i<=10;i++)
flag=flag && !(key[i] && !che[x][y][i]);
if(flag)
return false;
if('A'<=arr[x][y] && arr[x][y]<='J')
if(!key[arr[x][y]-'A']){
return false;
}
if('a'<=arr[x][y] && arr[x][y]<='j')
key[arr[x][y]-'a']=true;
for(int i=0;i<=10;i++)
if(key[i])
che[x][y][i]=true;
return true;
}
};
void fnd(state &p){
for(p.x=0;p.x<n;p.x++)
for(p.y=0;p.y<m;p.y++)
if(arr[p.x][p.y]=='@')
return;
}
int dfs(){
state s;
fnd(s);
s.time=0;
for(int i=0;i<=9;i++)
s.key[i]=false;
s.key[10]=true;
queue<state> q;
q.push(s);
while(q.empty()==false){
s=q.front();
if(arr[s.x][s.y]=='^')
return s.time;
for(int i=0;i<4;i++){
s=q.front();
if(s.can(i))
q.push(s);
}
q.pop();
}
return -1;
}
int main(){
while(~scanf("%d %d %d",&n,&m,&t)){
for(int i=0;i<n;i++)
scanf("%s",arr[i]);
memset(che,0,sizeof(che));
printf("%d\n",dfs());
}
return 0;
}
-------------------------------------------------------------
其实这个优化是只是用时间换空间 (谢柴爷提醒
每次判断都加了一个o(s) (s是钥匙的数量
的扫描