题意:
给一个n*m的矩阵,从11,走到nm,格子和格子之间可能有墙,也可能有门,有的格子上面有钥匙,相应的钥匙开相应的们,捡钥匙和开门都不需要时间,问你最少多少部能走到nm.
思路:
哎!一眼就看出来了是个状态压缩搜索的水题,结果wa了将近两个小时,就是因为忽略了一个点可能有多把钥匙,回来说下这个题,我们可以开一个数组mark[x][y][key],表示当前的这个点xy所含有的钥匙状态是key的时候是否走过,key是一个二进制压缩的数,这个很简单不解释,同时在开一个数组bnk[x1][y1][x2][y2]记录从x1y1到点x2y2的中间是什么东西(墙,门,或者什么都没有),然后就是遍历就行了,题目一点不难,还不明白的直接看代码就知道了。
#include<stdio.h>
#include<string.h>
#include<queue>
#define N 20
using namespace std;
typedef struct
{
int x ,y ,t ,key;
}NODE;
NODE xin ,tou;
int mark[N][N][1<<10+1];
int bank[N][N][N][N];
int map[N][N];
int dir[4][2] = {0 ,1 ,0 ,-1 ,1 ,0 ,-1 ,0};
int BFS(int n ,int m)
{
memset(mark ,0 ,sizeof(mark));
xin.x = xin.y = 1;
xin.t = 0;
xin.key = 0 | map[1][1];
mark[xin.x][xin.y][xin.key] = 1;
queue<NODE>q;
q.push(xin);
while(!q.empty())
{
tou = q.front();
q.pop();
for(int i = 0 ;i < 4 ;i ++)
{
xin.x = tou.x + dir[i][0];
xin.y = tou.y + dir[i][1];
xin.t = tou.t + 1;
if(xin.x < 1 || xin.x > n || xin.y < 1 || xin.y > m)
continue;
if(!bank[tou.x][tou.y][xin.x][xin.y])
continue;
if(bank[tou.x][tou.y][xin.x][xin.y] == -1 || tou.key & (1 << (bank[tou.x][tou.y][xin.x][xin.y] - 1)))
{
if(!map[xin.x][xin.y]) xin.key = tou.key;
else xin.key = tou.key | map[xin.x][xin.y];
if(!mark[xin.x][xin.y][xin.key])
{
mark[xin.x][xin.y][xin.key] = 1;
q.push(xin);
if(xin.x == n && xin.y == m)
return xin.t;
}
}
}
}
return -1;
}
int main ()
{
int n ,m ,p ,k ,q ,i;
int x1 ,x2 ,y1 ,y2 ,key;
while(~scanf("%d %d %d" ,&n ,&m ,&p))
{
scanf("%d" ,&k);
memset(bank ,255 ,sizeof(bank));
for(i = 1 ;i <= k ;i ++)
{
scanf("%d %d %d %d %d" ,&x1 ,&y1 ,&x2 ,&y2 ,&key);
bank[x1][y1][x2][y2] = bank[x2][y2][x1][y1] = key;
}
scanf("%d" ,&q);
memset(map ,0 ,sizeof(map));
for(i = 1 ;i <= q ;i ++)
{
scanf("%d %d %d" ,&x1 ,&y1 ,&key);
map[x1][y1] |= (1 << (key - 1));
}
printf("%d\n" ,BFS(n ,m));
}
return 0;
}