题目大意
给n*m的矩阵,要从S到T,途中有卫兵,其观察范围为曼哈顿距离<=xi,j(即该卫兵的视力),现在有2种技能,无使用冷却,有次数限制:
- 隐形,不被卫兵发现
- 瞬移,从普通转移的8联通变成4联通,距离为d,普通和瞬移用时均为1
求从S到T的最短用时,在用时最短的情况下,要求技能总次数最少,如果还有多种情况,要求隐形次数最少。
思路
首先,对于一个卫兵的观察范围,我们需要差分处理(TLE警告),因此,数组最少要开352(RE警告)。
然后,在bfs时,我们需要剪枝(TLE警告)如下:
- 如果现在的用时已经>之前的最优值时,break;
- 如果该点隐形x次,瞬移y次的情况已经有了,那么我们不需要处理ta,直接跳过
最后,我们需要考虑输出-1的情况。(WA警告)
code:
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
string x;
int a[361][361],sx,sy,ex,ey,n,m,cq,cm,d;
bool b[361][361];
int c[361][361][16][16];
int q[12][3]={
{
0,1,0},{
1,0,0},{
-1,0,0},{
0,-1,0},{
-1,-1,0},{
1,1,0},{
1,-1,0},{
-1,1,0},{
0,0,1},{
0,0,1},{
0,0,1},{
0,0,1}};
struct f{
int x,y,w,j,b;
} o,op;
queue<f> p;
int mn=0x7f7f7f7f,mnx,mny;
void bfs()
{
while (p.size())
{
o=p.front();
p.pop();
op.b=o.b+1;
if (op.b>mn) continue;
for (int i=0;i<=11;i++)
{
op.x=o.x+q[i][0],op.y=o.y+q[i][1],op.j=o.j+q[i][2];
if (op.x<1||op.x>n||op.y<1||op.y>m||op.j>cm||b[op.x][op.y]==1) continue;
op.w=o.w+(a[op.x][op.y]>0?1:0);
if (op.w>cq||c[op.x][op.y][op.w][op.j]) continue;
if (op.x==ex&&op.y==ey)
{
if (mn>op.b||(mn==op.b&&mnx+mny>op.w+op.j)||(mn==op.b&&mnx+mny==op.w+op.j&&mnx>op.w))
{
mn=op.b;
mnx=op.w;
mny=op.j;
}
}
c[op.x][op.y][op.w][op.j]=1;
p.push(op);
}
}
if (mn==0x7f7f7f7f) cout<<-1;
else cout<<mn<<' '<<mnx<<' '<<mny<<endl;
return;
}
int main()
{
cin>>n>>m>>cq>>cm>>d;
q[11][1]=d,q[10][1]=-d,q[9][0]=d,q[8][0]=-d;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
cin>>x;
if (x=="S")
{
sx=i,sy=j;
continue;
}
if (x=="T")
{
ex=i,ey=j;
continue;
}
if (x==".") continue;
int u=0;
for (int k=0;k<x.size();k++) u=u*10+x[k]-'0';
b[i][j]=1;
for (int ii=max(1,i-u+1);ii<=min(n,i+u-1);ii++)
{
int uu=min(m,j+u-1-abs(i-ii));
int jj=max(1,j-u+1+abs(i-ii));
a[ii][uu+1]--,a[ii][jj]++;
}
}
}
for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
{
a[i][j]+=a[i][j-1];
}
o.x=sx,o.y=sy;
c[sx][sy][0][0]=1;
p.push(o);
bfs();
return 0;
}