• 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
  • 相关阅读:
    Redis总结
    设计模式-单例模式
    spring5源码解读
    关于asp.net MVC 中的TryUpdateModel方法
    WebSocket在ASP.NET MVC4中的简单实现 (该文章转自网络,经尝试并未实现,请大神指点。)
    C# 新特性 dynamic的使用及扩展
    C#用反射判断一个类型是否是Nullable同时获取它的根类型(转自网络)
    C#通用类型转换 Convert.ChangeType 转自网络
    浅谈.NET反射机制的性能优化 转自网络 博客园
    浅析大型网站的架构 转自软件中国
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3983522.html
Copyright © 2020-2023  润新知