题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3442
题目大意:就是有ABCDE五种塔,(其实不是塔,但是还是可以把它们看成塔),然后每种塔有特定的攻击范围和攻击力,其中,只有C可以走,其他的塔不能走。我们要从起点走到终点,看是否能走到,能走到就要找最小的伤害值。
另外就是每种塔的攻击只能有一次。
题解:我们先将每个点的伤害预处理一下,然后就开始bfs,bfs我们采取的是得到到达终点的最小伤害值,如果不能到达终点就直接return-1。其实是可以不用优先队列的,因为我们是要得到所有能够到达终点的路径的伤害的最小值,我们有ans每次比较存储,所以不需要按照伤害值的大小在队列中排序,因为队列是要清空的最后。所以呢,可以直接用队列来做,没有什么区别的实际上。
需要注意的就是,这里说到了一个曼哈顿距离,影响到了塔的攻范围,所以百度一下曼哈顿距离是什么然后再做。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n,m;
char mp[55][55];
bool vis[55][55][50];
int sx,sy;
int dam[55][55];
const int dir[4][2]={
0,1,
1,0,
-1,0,
0,-1
};
const int hurt[5]={1,2,3,4,5};
const int range[5]={2,3,0,2,1};
struct node{
int x,y,state,hp;
node(int a=0,int b=0,int c=0,int d=0):x(a),y(b),state(c),hp(d){}
friend bool operator < (node n1,node n2)
{
return n1.hp>n2.hp;
}
};
bool InMap(int x,int y)
{
return x>=1&&x<=n&&y>=1&&y<=m;
}
bool IsTower(int x,int y)
{
return mp[x][y]=='A'||mp[x][y]=='B'||mp[x][y]=='D'||mp[x][y]=='E';
}
void f()
{
memset(dam,0,sizeof(dam));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int ttx,tty;
if(mp[i][j]>='A'&&mp[i][j]<='E')
{
int id=mp[i][j]-'A';
for(int ii=0;ii<=range[id];ii++)
{
for(int jj=range[id]-ii;jj>=0;jj--)
{
ttx=i+ii;
tty=j+jj;
if(InMap(ttx,tty))
dam[ttx][tty]|=(1<<id);
ttx=i-ii;
tty=j+jj;
if(InMap(ttx,tty))
dam[ttx][tty]|=(1<<id);
ttx=i+ii;
tty=j-jj;
if(InMap(ttx,tty))
dam[ttx][tty]|=(1<<id);
ttx=i-ii;
tty=j-jj;
if(InMap(ttx,tty))
dam[ttx][tty]|=(1<<id);
}
}
}
}
}
}
int bfs()
{
f();
int ans=INF;
int flag=0;
memset(vis,false,sizeof(vis));
priority_queue<node>q;
q.push(node(sx,sy,0,0));
vis[sx][sy][0]=true;
while(!q.empty())
{
for(int i=0;i<4;i++)
{
int tx=q.top().x+dir[i][0];
int ty=q.top().y+dir[i][1];
if(mp[tx][ty]=='#'||!InMap(tx,ty)||IsTower(tx,ty))
continue;
if(mp[tx][ty]!='!'&&!(dam[tx][ty]^0))//如果没有伤害,就直接push
{
if(vis[tx][ty][q.top().state])
continue;
q.push(node(tx,ty,q.top().state,q.top().hp));
vis[tx][ty][q.top().state]=true;
}
else
{
int state=q.top().state,tmp_hp=q.top().hp;
for(int j=0;j<=4;j++)
{
if(((dam[tx][ty]>>j)&1)&&!(q.top().state>>j&1))//之前没有受到过这儿的伤害
{
state|=1<<j;
tmp_hp+=hurt[j];
}
}
if(vis[tx][ty][state])
continue;
if(mp[tx][ty]=='!')//如果到了终点
{
flag=1;
if (ans > tmp_hp)
ans = tmp_hp;
vis[tx][ty][state] = true;
continue;
}
q.push(node(tx,ty,state,tmp_hp));
vis[tx][ty][state]=true;
}
}
q.pop();
}
if(flag==0)
return -1;
else
return ans;
}
int main()
{
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
scanf("%d%d",&n,&m);
getchar();
for(int j=1;j<=n;j++)
{
for(int k=1;k<=m;k++)
{
scanf("%c",&mp[j][k]);
if(mp[j][k]=='$')
{
sx=j;
sy=k;
mp[j][k]='.';
}
}
getchar();
}
printf("Case %d: %d\n",i,bfs());
}
return 0;
}