Three Kingdoms 【HDU - 3442】【BFS+状压】

题目链接


  序言:这道题其实是可以不用状压的,不过差别不大,状压思想会好些。

  题意:我们能走这么几块地'.'、'!'(终点)、'C'(会掉3滴血),还有几类塔,我们遇到它们的攻击范围的时候会受到相应的伤害'A'、'B'、'D'、'E',然后问我们刘备在经受最小伤害的时候到达终点的方案。还有:被某种武器伤害的可能只有一种,不会受到二次伤害。

  所以,题目就变得很简单了,我们只需要状压所有武器种类的状态,受过伤害的时候并且给自己叠加上这种武器的buff就可以了,如果下次再经过的时候就判断是否已经受到过相应的buff即可,然后再决定是否叠加伤害。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
inline int get_Range(char fu)
{
    switch (fu)
    {
        case 'A': return 2;
        case 'B': return 3;
        case 'C': return 0;
        case 'D': return 2;
        case 'E': return 1;
        default: return -1;
    }
}
int get_attact(int id)
{
    switch (id)
    {
        case 0: return 1;
        case 1: return 2;
        case 2: return 3;
        case 3: return 4;
        case 4: return 5;
        default: return 0;
    }
}
const int maxN = 55;
const int dir[4][2] =
{
    -1, 0,
    0, -1,
    0, 1,
    1, 0
};
int N, M, sx, sy, val[maxN][maxN], ans;
char mp[maxN][maxN];
bool vis[maxN][maxN][maxN];
bool In_Map(int x, int y) { return x>=1 && x<=N && y>=1 && y<=M; }
struct node
{
    int x, y, blood, state;
    node(int a=0, int b=0, int c=0, int d=0):x(a), y(b), blood(c), state(d) {}
    friend bool operator < (node e1, node e2) { return e1.blood > e2.blood; }
};
void let_Do(int th, int x, int y, int range)
{
    for(int i=0; i<=range; i++) for(int j=0; j<=range-i; j++)
    {
        val[x+i][y+j] |= (1<<th);
        val[x-i][y+j] |= (1<<th);
        val[x-i][y-j] |= (1<<th);
        val[x+i][y-j] |= (1<<th);
    }
    if(th == 2) val[x][y] |= (1<<th);
}
inline void pre_did()   //得到每个点会收到那些塔的伤害的种类
{
    ans = -1;   //初始化最后的ans,就是说明能否走到最后的终点
    memset(val, 0, sizeof(val));
    for(int i=1; i<=N; i++)
    {
        for(int j=1; j<=M; j++)
        {
            if(mp[i][j] >= 'A' && mp[i][j] <= 'E') let_Do(mp[i][j]-'A', i, j, get_Range(mp[i][j]));    //因为C是只有站上去才会产生伤害
        }
    }
}
int get_damaged(int &state, int now) //state是上一个状态,now是目前节点的会收到的伤害的种类,受过了就不会再受了
{
    int res = 0, last = state;
    state |= now;
    for(int i=0; i<5; i++) if(((last>>i)&1) != ((state>>i)&1)) res += get_attact(i);
    return res;
}
void bfs()
{
    priority_queue<node> Q;
    memset(vis, false, sizeof(vis));
    Q.push(node(sx, sy));
    vis[sx][sy][0] = true;
    while(!Q.empty())
    {
        node tmp = Q.top(); Q.pop();
        int xx, yy, state = tmp.state;
        for(int i=0; i<4; i++)
        {
            state = tmp.state;
            xx = tmp.x + dir[i][0]; yy = tmp.y + dir[i][1];
            if(!In_Map(xx, yy) || mp[xx][yy] == '#' || (mp[xx][yy]>='A' && mp[xx][yy]<='E' && mp[xx][yy]!='C')) continue;
            else if(mp[xx][yy] == '!')
            {
                int det_blood = get_damaged(state, val[xx][yy]);
                if(vis[xx][yy][state]) continue;
                vis[xx][yy][state] = true;
                ans = (ans == -1?(tmp.blood+det_blood):(min(tmp.blood+det_blood, ans)));
                return;
            }
            else
            {
                int det_blood = get_damaged(state, val[xx][yy]);
                if(vis[xx][yy][state]) continue;
                vis[xx][yy][state] = true;
                Q.push(node(xx, yy, tmp.blood+det_blood, state));
            }
        }
    }
}
int main()
{
    int T;  scanf("%d", &T);
    for(int Cas=1; Cas<=T; Cas++)
    {
        scanf("%d%d", &N, &M);
        for(int i=1; i<=N; i++)
        {
            scanf("%s", mp[i]+1);
            for(int j=1; j<=M; j++)
            {
                if(mp[i][j] == '$') { sx = i; sy = j; mp[i][j] = '.'; }
            }
        }
        pre_did();
        bfs();
        printf("Case %d: %d\n", Cas, ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/84915449