zoukankan      html  css  js  c++  java
  • 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
    ",mini);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    CCF CSP 题解
    CCF CSP 2019032 二十四点
    CCF CSP 2018121 小明上学
    CCF CSP 2019092 小明种苹果(续)
    CCF CSP 2019091 小明种苹果
    CCF CSP 2019121 报数
    CCF CSP 2019031 小中大
    CCF CSP 2020061 线性分类器
    CCF CSP 2020062 稀疏向量
    利用国家气象局的webservice查询天气预报(转载)
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3983522.html
Copyright © 2011-2022 走看看