原文链接: HDU 4771 Stealing Harry Potter's Precious
上一篇: HDU 1242 bfs
下一篇: HDU 1429 bfs 状态压缩
题意:
给定n*m的地图
#为墙 @为起点
下面K个坐标
问:遍历K个给定坐标,需要的最小步数
思路:
因为K 最大只有4
状压 当前是否走过某点
用二进制 的 i 位 0、1表示 第i个点是否走过
也可以初始化宝藏为1<<i,这样判断和赋值会方便一点
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define LL long long
int const MAX = 111;
int const INF = 1 << 30;
using namespace std;
int mp[MAX][MAX], n, m, k;
char tmp[MAX];
//vis[x][y][s] 表示经过x,y点,状态s
bool vis[MAX][MAX][20];
struct Node {
int x, y, step, state;
Node(int x = 0, int y = 0, int state = 0, int step = 0) : x(x), y(y), step(step), state(state){ }
};
int dir[4][2] = { 1, 0, -1, 0, 0, 1, 0, -1 };
void setvis(Node nd){
vis[nd.x][nd.y][nd.state] = 1;
}
int bfs(Node st){
queue<Node> q;
q.push(st);
setvis(st);
while(!q.empty()){
Node t = q.front();
q.pop();
// printf("(%d %d %d %d )\n", t.x, t.y, t.state, t.step);
if(t.state == ( 1 << k ) - 1){
return t.step;
}
for(int k = 0 ; k < 4 ; k++){
int nx = t.x + dir[k][0], ny = t.y + dir[k][1], ns;
if(nx < 1 || nx > n || ny < 1 || ny > m || mp[nx][ny] == -1)
continue;
if(mp[nx][ny] == 0)
ns = t.state;
else
ns = t.state | 1 << ( mp[nx][ny] - 1 );
if(vis[nx][ny][ns] == 0){
q.push(Node(nx, ny, ns, t.step + 1));
setvis(Node(nx, ny, ns));
}
}
}
return -1;
}
int main(int argc, char* argv[]){
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
while(scanf("%d %d", &n, &m) != EOF && ( n || m )){
//出发节点
Node st;
for(int i = 1 ; i <= n ; i++){
scanf("%s", tmp + 1);
for(int j = 1 ; j <= m ; j++){
mp[i][j] = tmp[j] == '#' ? -1 : 0;
if(tmp[j] == '@')
st.x = i, st.y = j, st.step = st.state = 0;
}
}
int x, y;
scanf("%d", &k);
for(int i = 1 ; i <= k ; i++){
scanf("%d %d", &x, &y);
mp[x][y] = i;
}
/*
//输出迷宫,0可走,-1障碍,1-k是宝藏同时也是编号
printf("st:(%d,%d)\n", st.x, st.y);
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= m ; j++)
printf("%d%c", mp[i][j], j == m ? '\n' : ' ');
*/
memset(vis, 0, sizeof( vis ));
printf("%d\n", bfs(st));
}
return 0;
}