题目链接
序言:这道题其实是可以不用状压的,不过差别不大,状压思想会好些。
题意:我们能走这么几块地'.'、'!'(终点)、'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;
}