hdu 5025 Saving Tang Monk[状态压缩bfs]( 2014 ACM/ICPC Asia Regional Guangzhou Online)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5025

比赛的时候自己也在写这个。。但是,最后没有写出来。。不是自己写不出来。。只是,当时,思路已经很是混乱了。。表示心情很是糟糕。。其他队也已经a了。也没有心情写了。。很显然,自己比赛时的心态有待改观。。特别是正式的比赛中,心情应该比较平静。。。

题目意思:
孙悟空要救唐三藏,每杀一个蛇需要额外+1时间。钥匙必须是按顺序拿的。。

钥匙最多9把,蛇最多5个。。。

之前自己对于相同的对象,自己不知道怎么来区分,表示,又学习了,对于 相同的对象,我们可以标示他们为不同的对象。。。。。。- - 。。这也很符合人们的基本逻辑思想的。。。。

自己刚开始的做法是对钥匙和蛇一起压缩。。。但是,这样是会MLE的。。。

我们可以发现的是,我们必须按顺序来拿钥匙。。这是这个问题的突破点。。钥匙的状态直接减到10。。很的轻松。。。

Code:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <queue>
#include <stack>

using namespace std;
const int N = 104;
const int dx[] = {0, 0, -1, 1};
const int dy[] = {1, -1, 0, 0};
int n, m, bx, by;
bool vis[N][N][10][(1 << 5) + 1];
char map[N][N];

struct Node
{
    int x, y;
    int step, key, s;
    Node(){}
    Node(int a, int b, int sx, int k, int sn){
        x = a; y = b;
        step = sx; key = k;
        s = sn;
    }
};

bool operator < (Node a, Node b)
{
    if(a.step > b.step) return true;
    return false;
}


void bfs()
{
    memset(vis, 0, sizeof(vis));
    priority_queue<Node> q;
    q.push(Node(bx, by, 0, 0, 0));
    vis[bx][by][0][0] = true;
    while(!q.empty()){
        Node tmp1 = q.top(), tmp2;
        q.pop();
//        printf("%d %d key = %d snake = %d step = %d\n", tmp1.x, tmp1.y, tmp1.key, tmp1.s ,tmp1.step);
        if(map[tmp1.x][tmp1.y] == 'T' && tmp1.key == m){
            printf("%d\n", tmp1.step);
            return ;
        }

        for(int i = 0; i < 4; i ++){
            tmp2.x = tmp1.x + dx[i]; tmp2.y = tmp1.y + dy[i];
            if(tmp2.x > n || tmp2.x < 1 || tmp2.y > n || tmp2.y < 1 || map[tmp2.x][tmp2.y] == '#') continue;
//            printf("%d %d %c\n", tmp2.x, tmp2.y, map[tmp2.x][tmp2.y]);
            if(map[tmp2.x][tmp2.y] >= 'a' && map[tmp2.x][tmp2.y] <= 'e'){
                int snakenum = map[tmp2.x][tmp2.y] - 'a';
                tmp2.key = tmp1.key;
                if(tmp1.s & (1 << snakenum)){
                    tmp2.step = tmp1.step + 1;
                    tmp2.s = tmp1.s;
                }
                else {
                    tmp2.s = tmp1.s | (1 << snakenum);
                    tmp2.step = tmp1.step + 2;
                }
                if(!vis[tmp2.x][tmp2.y][tmp2.key][tmp2.s]){
                    q.push(tmp2);
                    vis[tmp2.x][tmp2.y][tmp2.key][tmp2.s] = true;
                }
            }
            else {
                if(map[tmp2.x][tmp2.y] > '0' && map[tmp2.x][tmp2.y] <= '9'){
                    int keynum = map[tmp2.x][tmp2.y] - '0';
                    if(tmp1.key == keynum - 1){
                        tmp2.key = tmp1.key + 1;
                    }
                    else tmp2.key = tmp1.key;
                    tmp2.step = tmp1.step + 1;
                    tmp2.s = tmp1.s;
                    if(!vis[tmp2.x][tmp2.y][tmp2.key][tmp2.s]){
                        q.push(tmp2);
                        vis[tmp2.x][tmp2.y][tmp2.key][tmp2.s] = true;
                    }
                }
                else {
                    tmp2.key = tmp1.key;
                    tmp2.s = tmp1.s;
                    tmp2.step = tmp1.step + 1;
                    if(!vis[tmp2.x][tmp2.y][tmp2.key][tmp2.s]){
                        q.push(tmp2);
                        vis[tmp2.x][tmp2.y][tmp2.key][tmp2.s] = true;
                    }
                }
            }
        }
    }
    puts("impossible");
}

int main()
{
//    freopen("1.txt", "r", stdin);
    while(scanf("%d %d", &n, &m) && (n || m)){
        getchar();
        int snake = 0;
        for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= n; j ++){
                scanf("%c", &map[i][j]);
                if(map[i][j] == 'K') bx = i, by = j;
                if(map[i][j] == 'S') map[i][j] = 'a' + snake ++;
            }
            getchar();
        }
        bfs();
    }
    return 0;
}

比较DT的问题是。。。自己交G++ AC。。 C++ TLE。。。

很是无语。。。。。三观尽毁。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值