原题链接
简洁题意:
从 S S S到 T T T,单位时间可以走格子周围的八个格子,有些格子不能走,这些格子周围距离小于等于 a ( i , j ) a(i,j) a(i,j)的格子只能用一次技能一才能走。每个时刻可以用技能二,单位时间向上下左右走 d d d格。问最快多久,若多种方案则希望技能用得少,技能用的一样多则希望少用技能一,无解输出 − 1 -1 −1,反之输出时间和各个技能用的数量。
分析:
数据范围不大,可以用
b
f
s
bfs
bfs,直到答案大于当前答案或者不能走就停止,到达
T
T
T后对比答案并更新,周围能观察到的点就搜索覆盖。但是这样仍然会超时,因为我们处理一个点所能影响的周围的点太慢了。不难发现这个是一个菱形,可以针对每一个菱形的每一行进行差分,最后统一处理。注意在处理字符时
a
(
i
,
j
)
a(i,j)
a(i,j)有可能有两位。
差分最后统计的时间复杂度是
Θ
(
n
m
)
\Theta(nm)
Θ(nm)的,
b
f
s
bfs
bfs每个点都出入队一次,时间复杂度
Θ
(
n
m
)
\Theta(nm)
Θ(nm),总共最多枚举
n
2
m
2
n^2m^2
n2m2条边,所以总的时间复杂度是
O
(
n
2
m
2
)
O(n^2m^2)
O(n2m2)的。这样时间会刚好超一点,但是实际使用起来是不可能出现每两个点之间都可以互相到达的情况,
n
2
m
2
n^2m^2
n2m2条边也不可能都用了,大大达不到上界时间复杂度。
代码:
#include<bits/stdc++.h>
using namespace std;
const int NN=354,dx[8]={1,-1,0,0,1,-1,1,-1},dy[8]={0,0,1,-1,1,1,-1,-1};
int n,m,c1,c2,d,sta[NN][NN],num[NN][NN];
bool can[NN][NN],vis[NN][NN][20][20];
struct node
{
int x,y,d,c1,c2;
}q[30000004],ans=(node){0,0,1e9,1e9,1e9};
void cover(int x,int y,int k)
{
for(int i=0;i<k;i++)
{
num[max(1,x-i)][max(1,y-k+i+1)]++;
num[max(1,x-i)][min(m,y+k-i-1)+1]--;
num[min(n,x+i)][max(1,y-k+i+1)]++;
num[min(n,x+i)][min(m,y+k-i-1)+1]--;
}
}
bool check(node x,node y)
{
if(x.c1+x.c2!=y.c1+y.c2)
return x.c1+y.c2<y.c1+y.c2;
return x.c1<y.c1;
}
void bfs(pair<int,int>st,pair<int,int>ed)
{
int h=1,t=0;
q[++t]=(node){st.first,st.second};
while(h<=t)
{
node u=q[h++];
if(u.d>=ans.d)
break;
for(int i=0;i<8;i++)
{
int nx=u.x+dx[i],ny=u.y+dy[i];
if(nx<1||ny<1||nx>n||ny>m||sta[nx][ny])
continue;
if(!can[nx][ny])
{
if(vis[nx][ny][u.c1][u.c2])
continue;
vis[nx][ny][u.c1][u.c2]=true;
q[++t]=(node){nx,ny,u.d+1,u.c1,u.c2};
if(nx==ed.first&&ny==ed.second&&check(q[t],ans))
ans=q[t];
}
else
{
if(u.c1>=c1||vis[nx][ny][u.c1+1][u.c2])
continue;
vis[nx][ny][u.c1+1][u.c2]=true;
q[++t]=(node){nx,ny,u.d+1,u.c1+1,u.c2};
if(nx==ed.first&&ny==ed.second&&check(q[t],ans))
ans=q[t];
}
}
for(int i=0;i<4;i++)
{
int nx=u.x+dx[i]*d,ny=u.y+dy[i]*d;
if(nx<1||ny<1||nx>n||ny>m||sta[nx][ny])
continue;
if(!can[nx][ny])
{
if(u.c2>=c2||vis[nx][ny][u.c1][u.c2+1])
continue;
vis[nx][ny][u.c1][u.c2+1]=true;
q[++t]=(node){nx,ny,u.d+1,u.c1,u.c2+1};
if(nx==ed.first&&ny==ed.second&&check(q[t],ans))
ans=q[t];
}
else
{
if(u.c1>=c1||u.c2>=c2||vis[nx][ny][u.c1+1][u.c2+1])
continue;
vis[nx][ny][u.c1+1][u.c2+1]=true;
q[++t]=(node){nx,ny,u.d+1,u.c1+1,u.c2+1};
if(nx==ed.first&&ny==ed.second&&check(q[t],ans))
ans=q[t];
}
}
}
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&c1,&c2,&d);
pair<int,int>st,ed;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
char s[10];
scanf("%s",s);
if(s[0]=='S')
{
st.first=i;
st.second=j;
}
else if(s[0]=='T')
{
ed.first=i;
ed.second=j;
}
else if(s[0]!='.')
{
for(int k=0;s[k];k++)
sta[i][j]=(sta[i][j]<<3)+(sta[i][j]<<1)+(s[k]-'0');
cover(i,j,sta[i][j]);
}
}
for(int i=1;i<=n;i++)
{
int sum=0;
for(int j=1;j<=m;j++)
{
sum+=num[i][j];
if(sum>0)
can[i][j]=true;
}
}
bfs(st,ed);
if(!ans.x)
printf("-1");
else
printf("%d %d %d",ans.d,ans.c1,ans.c2);
return 0;
}