P4011 孤岛营救问题(压状+bfs最短路)
题目描述:
给我们一个矩形地图,地图上有一些路径需要特定的钥匙才能走,有些路径不能走,钥匙散落在地图上,
问最少需要多少步能从(1,1)走到(m,n)。
数据范围,1<=m<=n<=10,钥匙数量1<=k<=10;
思路;对每个点压状,用dp[x][y][s]表示走到(x,y)时手里有钥匙集合s的最小步数,而由于路径长度都是1,
所以直接用bfs求解,而且每次到达每个点时,这个点的最小步数就确定了。
但是我没过,我对着题解看了半天也没过,吐了
代码(没过):
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 10000005; const int inf = 0x3f3f3f3f; int dx[4] = { -1,1,0,0 }; int dy[4] = { 0,0,1,-1 }; int f[11][11][11][11]; int cnt[11][11]; int key[11][11][11]; bool vis[11][11][2048]; int n, m, p,k,s; struct point { int x, y, cos, len; }; int bfs(int x, int y) { queue<point>q; int nows = 0; for (int i = 1; i <= cnt[x][y]; i++) {//把起点的钥匙拿上 nows |= (1<<(key[x][y][i] - 1)); } vis[x][y][nows] = 1; q.push({ x,y,nows,0}); while (!q.empty()) { point p = q.front(); q.pop(); if (p.x == m && p.y == n) { return p.len; } for (int d = 0; d < 4; d++) { int tx = p.x + dx[d]; int ty = p.y + dy[d]; int pres = p.cos,opt = f[p.x][p.y][tx][ty]; if (tx<1 || tx>m || ty<1 || ty>n||opt<0||(opt&& !(pres & (1 << (opt - 1)))))continue; //超届,不能走,能走但是需要的钥匙没拿到三种情况都不能移动 //第一次移动到一个位置时,到达那个位置的时间一定是最短的,这也就是我们走到终点直接输出结果的原因 for (int i = 1; i < cnt[tx][ty]; i++) {//把目的位置的钥匙拿上 pres |= (1<<(key[tx][ty][i] - 1)); } if (vis[tx][ty][pres])continue;//走过了 vis[tx][ty][pres] = 1; q.push({ tx,ty,pres,p.len + 1 });//进入 } } return -1; } int main() { freopen("test.txt", "r", stdin); scanf("%d%d%d%d", &m, &n, &p,&k); for (int i = 1; i <= k; i++) { int x1, y1, x2, y2, c; scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c); if (c)f[x1][y1][x2][y2]=f[x2][y2][x1][y1] = c;//可以走,需要钥匙 else f[x1][y1][x2][y2]=f[x2][y2][x1][y1] = -1;//不能走 } int num; scanf("%d", &num); for (int i = 1; i <= num; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); key[a][b][++cnt[a][b]] = c;//该位置放置有那些钥匙 } printf("%d\n", bfs(1, 1)); return 0; }