hdu 1429 胜利大逃亡(续) (bfs+状态压缩)
又开始刷题了
题意:略过。
分析:主要是确定状态量,除了坐标(x,y)之外,还有一个key状态,就好比手上拿着一串钥匙。状态可以用位运算来表示:key&(x,y)表示判断有没有这扇门的钥匙,key|(x,y)表示捡起了一把钥匙。
错误:1、开标记数组mark[][][],key状态大小顺手开成key,其实应该是1<<key
2、判断应该先判wall(),顺序颠倒倒是RE(访问越界)
3、key<=10:只有 a-j 共10种钥匙
思考:这道题其实应该是有漏洞的,因为魔王只是查看男主是否在原位置上,并没有说明检查钥匙,如此一来男主只要在时间限定T之内找到一把钥匙,就向逃亡迈进了一步,换句话说就是状态被大幅度增加——不再是必须在T内找到出口“^”。进一步说,若魔王发现男主不在原位置,不仅把他放回原位,还还原钥匙的位置,那么如果在时间限定T内,他能够找到钥匙并返回原位,又是否算是通过了这次检查呢?以上两种情况但凡一种成立,测试样例2都可以通过。
1 #include<cstdio> 2 #include<cstring> 3 #include<cctype> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 8 const int MAXN=22; 9 const int KEY=10; 10 11 int dir[4][2]={0,-1,0,1,-1,0,1,0}; 12 13 struct Node{ 14 int x,y,t,key; 15 Node(){} 16 Node(int _x,int _y,int _t,int _key):x(_x),y(_y),t(_t),key(_key){} 17 }; 18 19 char g[MAXN][MAXN]; 20 int mark[MAXN][MAXN][1<<KEY]; 21 queue<Node>q; 22 23 int n,m,T; 24 25 bool wall(int x,int y) 26 { 27 if(x<0||x>=n||y<0||y>=m) 28 return true; 29 if(g[x][y]=='*') 30 return true; 31 return false; 32 } 33 34 int Num(char ch) 35 { 36 return ch-(isupper(ch)?'A':'a'); 37 } 38 39 int bfs(int sx,int sy) 40 { 41 while(!q.empty()) 42 q.pop(); 43 44 memset(mark,0,sizeof(mark)); 45 q.push(Node(sx,sy,0,0)); 46 while(!q.empty()) 47 { 48 Node e=q.front();q.pop(); 49 50 if(e.t>=T) 51 break; 52 53 for(int i=0;i<4;i++) 54 { 55 int dx=e.x+dir[i][0]; 56 int dy=e.y+dir[i][1]; 57 int dt=e.t+1; 58 int dkey=e.key; 59 60 char ch=g[dx][dy]; 61 62 if(wall(dx,dy)) 63 continue; 64 if(dt>=T||mark[dx][dy][dkey]) 65 continue; 66 if(isupper(ch)&&!(dkey&(1<<Num(ch)))) 67 continue; 68 if(islower(ch)) 69 dkey=dkey|(1<<Num(ch)); 70 71 if(g[dx][dy]=='^') 72 return dt; 73 74 mark[dx][dy][dkey]=1; 75 q.push(Node(dx,dy,dt,dkey)); 76 } 77 } 78 return -1; 79 } 80 81 int main() 82 { 83 while(~scanf("%d%d%d",&n,&m,&T)) 84 { 85 for(int i=0;i<n;i++) 86 scanf("%s",g[i]); 87 88 int sx,sy,ex,ey; 89 for(int i=0;i<n;i++) 90 for(int j=0;j<m;j++) 91 if(g[i][j]=='@'){ 92 sx=i; 93 sy=j; 94 g[i][j]='.'; 95 } 96 97 printf("%d\n",bfs(sx,sy)); 98 } 99 return 0; 100 }