HDU 5025 Saving Tang Monk --BFS

题意:给一个地图,孙悟空(K)救唐僧(T),地图中'S'表示蛇,第一次到这要杀死蛇(蛇最多5条),多花费一分钟,'1'~'m'表示m个钥匙(m<=9),孙悟空要依次拿到这m个钥匙,然后才能去救唐僧,集齐m个钥匙之前可以经过唐僧,集齐x个钥匙以前可以经过x+1,x+2..个钥匙,问最少多少步救到唐僧。

解法:BFS,每个节点维护四个值:

x,y : 当前坐标

key :已经集齐了key个钥匙

step:已经走了多少步

S :   蛇的访问状态 (2^5的数表示,某位为1表示已经杀过了)

然后把唐僧看做钥匙m+1,再加点优化:

为了避免超时,用一个全局的dis[x][y][key][S] 表示到(x,y),已经集齐到key个钥匙,蛇的访问状态为S时的最小步数,如果BFS扩展的时候,当前状态的步数>=dis[当前状态],那么就不再扩展下去了。

BFS中的逻辑就很简单了,看代码吧。

最后,枚举蛇的状态S,取dis[x][y][m+1][S]的最小值即为最小步数。

代码:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#include <algorithm>

#include <queue>

#include <map>

#define INF 0x3f3f3f3f

using namespace std;

#define N 1000007



int dis[104][104][12][33],Stot,M;

struct node

{

    int x,y,key,step,S;

};

int dx[4] = {0,0,1,-1};

int dy[4] = {1,-1,0,0};

map<pair<int,int>,int> snake;

char ss[105][105];

int n,m;



bool OK(int nx,int ny)

{

    if(nx < n && nx >= 0 && ny < n && ny >= 0 && ss[nx][ny] != '#')

        return true;

    return false;

}



void bfs(node s)

{

    queue<node> que;

    que.push(s);

    while(!que.empty())

    {

        node now = que.front();

        que.pop();

        int nx = now.x, ny = now.y;

        int key = now.key, step = now.step;

        int S = now.S;

        node tmp;

        for(int k=0;k<4;k++)

        {

            int kx = nx + dx[k];

            int ky = ny + dy[k];

            if(!OK(kx,ky)) continue;

            tmp.x = kx,tmp.y = ky;

            if(ss[kx][ky] == 'S')                    //

            {

                int ind = snake[make_pair(kx,ky)];   //是第几条蛇

                tmp.key = key;

                if(S & (1<<(ind-1)))                 //如果已经杀死

                {

                    tmp.S = S;

                    tmp.step = step+1;

                } 

                else                                 //否则要杀

                {

                    tmp.S = S|(1<<(ind-1));

                    tmp.step = step+2;

                }

                if(tmp.step < dis[kx][ky][tmp.key][tmp.S])

                {

                    dis[kx][ky][tmp.key][tmp.S] = tmp.step;

                    que.push(tmp);

                }

            }

            else if(ss[kx][ky] >= '1' && ss[kx][ky] <= '9')  //钥匙点

            {

                int num = ss[kx][ky] - '0';

                tmp.step = step+1;

                tmp.S = S;

                if(num == key+1)                             //正好是要拿的那个

                    tmp.key = key+1;

                else

                    tmp.key = key;

                if(tmp.step < dis[kx][ky][tmp.key][tmp.S])

                {

                    dis[kx][ky][tmp.key][tmp.S] = tmp.step;

                    que.push(tmp);

                }

            }

            else if(ss[kx][ky] == '$')   //唐僧这个点

            {

                tmp.key = key;

                tmp.S = S;

                tmp.step = step+1;

                if(M == key+1)           //已经集齐了所有钥匙,不再扩展,更新dis即可

                    dis[kx][ky][M][S] = min(dis[kx][ky][M][S],step+1);

                else                     //没有集齐,继续走

                    que.push(tmp);

            }

            else if(ss[kx][ky] == '.')

            {

                tmp.key = key;

                tmp.S = S;

                tmp.step = step+1;

                if(tmp.step < dis[kx][ky][tmp.key][tmp.S])

                {

                    dis[kx][ky][tmp.key][tmp.S] = tmp.step;

                    que.push(tmp);

                }

            }

        }

    }

}



int main()

{

    int Sx,Ex,Sy,Ey;

    int i,j;

    while(scanf("%d%d",&n,&m)!=EOF && n+m)

    {

        if(n == 1)

        {

            puts("impossible");

            continue;

        }

        snake.clear();

        Stot = 0;

        M = m+1;

        for(i=0;i<n;i++)

        {

            scanf("%s",ss[i]);

            for(j=0;j<n;j++)

            {

                if(ss[i][j] == 'K')

                    Sx = i,Sy = j, ss[i][j] = '.';

                else if(ss[i][j] == 'T')

                    Ex = i,Ey = j, ss[i][j] = '$';

                else if(ss[i][j] == 'S')

                    snake[make_pair(i,j)] = ++Stot;

            }

        }

        node tmp;

        tmp.x = Sx,tmp.y = Sy,tmp.key = 0,tmp.step = 0,tmp.S = 0;

        memset(dis,INF,sizeof(dis));

        dis[Sx][Sy][0][0] = 0;

        bfs(tmp);

        int mini = INF;

        for(i=0;i<(1<<Stot);i++)

            mini = min(mini,dis[Ex][Ey][M][i]);

        if(mini == INF)

            puts("impossible");

        else

            printf("%d\n",mini);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(HDU)