hdu-5025 Saving Tang Monk (BFS + 状态压缩)

该题是比较简单的BFS 。    难点在于多了两个限制条件 : 必须按照顺序捡拾钥匙 ; 杀死蛇消耗2单位时间,蛇只会被杀死一次 。

因为在拿到第n把钥匙前必须拿到第n-1把,所以只需要加一维大小是11的维度来维护当前拿到的钥匙情况就可以完整的表示所有状态了 。

但是还有蛇的条件,所以不妨在结构体里加一个正数,将其压缩成一个集合表示第i只蛇是不是被杀死了 。  所以事先对所有的蛇进行编号就行了 、

那么为什么蛇这个条件不用增加维度来维护呢?  原因很简单,仔细想想就会发现,蛇不是重点,不是最短路所必须维护的东西 ,是否经过蛇不是一个必要条件,但是对于最短路长度来说又是必须维护的,所以这样可以降低时间复杂度 。

由于所有状态最多经过一次,所以数组d[][][]的大小就是估算的时间复杂度 。

细节参见代码:

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 105;
int n,m,d[maxn][maxn][11];
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};
char s[maxn][maxn];
struct node{
    int r,c,id,s;
    node(int r = 0,int c = 0,int id = 0,int s=0) : r(r),c(c),id(id),s(s) {}
};
node K,T,ans_cur;
int bfs() {
    queue<node> q;
    K.s = 0;
    memset(d,-1,sizeof(d));
    q.push(K);
    d[K.r][K.c][K.id] = 0;
    while(!q.empty()) {
        node u = q.front(); q.pop();
        if(u.r == T.r && u.c == T.c && u.id == T.id) return  d[u.r][u.c][u.id];
        for(int i=0;i<4;i++) {
            int x = u.r + dx[i];
            int y = u.c + dy[i];
            node v = node(x,y,u.id,u.s);
            bool ok = false;
            if(x < 1 || x > n || y < 1 || y > n || s[x][y] == '#') continue;
            if(isdigit(s[x][y]) && v.id == s[x][y]-'0'-1) v.id++; //判断该钥匙是否可以捡拾
            if(islower(s[x][y])) {    //判断该蛇是否杀过
                int vv = s[x][y] - 'a';
                if(v.s & (1<<vv)) ;
                else { v.s |= 1<<vv; ok = true; }
            }
            if(d[v.r][v.c][v.id] < 0) {
                if(!ok) d[v.r][v.c][v.id] = d[u.r][u.c][u.id] + 1;
                else d[v.r][v.c][v.id] = d[u.r][u.c][u.id] + 2;
                q.push(v);
            }
        }
    }
    return -1;
}
int main() {
    while(~scanf("%d%d",&n,&m)) {
        if( !n && !m ) return 0;
        for(int i=1;i<=n;i++) {
            scanf("%s",s[i]+1);
        }
        int cnt = 0;
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=n;j++) {
                if(s[i][j] == 'K') K = node(i,j,0);
                else if(s[i][j] == 'T') T = node(i,j,m);
                else if(s[i][j] == 'S') s[i][j] = (char)('a' + cnt++); //将蛇编号
            }
        }
        int ans = bfs();
        if(ans == -1) printf("impossible\n");
        else printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(搜索,ACM,bfs,ACM-ICPC)