一个简单的搜索题了
不过有钥匙开门什么的其他条件
(好吧这都不是重点
这题一般的做法应该是状态压缩
就是用一个小于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是钥匙的数量
的扫描