https://ac.nowcoder.com/acm/contest/5278/K
题意:
给一个nm矩阵,上下左右走,求从s到t的最少时间。
有一次机会一步从 ( i , j ) (i,j) (i,j)走到 ( [ i − d , i − d ] , [ j − d , j + d ] ) ([i-d,i-d],[j-d,j+d]) ([i−d,i−d],[j−d,j+d]),花费时间也是1。
要求给出路径
解析:
跑一遍从s到每个点的最短路,从每个点到t的最短路。
接下来就是对于每个点,求矩阵范围内的最小值。
由于矩阵的大小均为 ( 1 + 2 d ) ( 1 + 2 d ) (1+2d)(1+2d) (1+2d)(1+2d),所以可以线性处理。
从横着处理一遍,对于每个点 ( i , j ) (i,j) (i,j),求出 ( i , j − 1 − 2 d ) (i,j-1-2d) (i,j−1−2d)到 ( i , j ) (i,j) (i,j)的最小值。(单调栈)
然后竖着处理,对于每个点,得到左上角的矩阵的最小值。
代码:
/*
* Author : Jk_Chen
* Date : 2020-04-18-12.52.13
*/
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=1e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
int n,m,d;
char Map[4009][4009];
pill link1[2009][2009];
pill link2[2009][2009];
int dis1[4009][4009];
const int di[4][2]={1,0,0,-1,0,1,-1,0};
void bfs(pill st,int dis[][4009],pill link[][2009]){
rep(i,1,n)rep(j,1,m)dis[i][j]=inf;
dis[st.fi][st.se]=0;
queue<pill>Q;
Q.push({st.fi,st.se});
while(!Q.empty()){
pill P=Q.front();Q.pop();
// test(P.fi,P.se,dis[P.fi][P.se]);
rep(i,0,3){
int x=P.fi+di[i][0];
int y=P.se+di[i][1];
if(x<1||x>n||y<1||y>m||Map[x][y]=='X')continue;
if(dis[x][y]>dis[P.fi][P.se]+1){
dis[x][y]=dis[P.fi][P.se]+1;
link[x][y]=P;
Q.push({x,y});
}
}
}
}
namespace DoubleFind{
int n,m,d;
int val[4009][4009];
int Min[4009][4009];
pill Ans[4009][4009];
void init(){
int len=1+2*d;
rep(i,1,n){
deque<int>Q;
int r=0;
int l=0-len+1;
while(r<m+d){
if(!Q.empty()&&Q.front()==l)Q.pop_front();
l++;
r++;
if(r<=m){
while(!Q.empty()&&val[i][r]<=val[i][Q.back()])
Q.pop_back();
Q.push_back(r);
}
Min[i][r]=Q.front();
}
}
rep(j,1,m+d){
deque<int>Q;
int r=0;
int l=0-len+1;
while(r<n+d){
if(!Q.empty()&&Q.front()==l)Q.pop_front();
l++;
r++;
if(r<=n){
while(!Q.empty()&&val[r][Min[r][j]]<=val[Q.front()][Min[Q.front()][j]])Q.pop_back();
Q.push_back(r);
}
Ans[r][j]={Q.front(),Min[Q.front()][j]};
}
}
}
int Findval(int xmax,int ymax){
return val[Ans[xmax][ymax].fi][Ans[xmax][ymax].se];
}
}
int main(){
pill s,t;
scanf("%d%d%d",&n,&m,&d);
DoubleFind::n=n;
DoubleFind::m=m;
DoubleFind::d=d;
rep(i,1,n){
scanf("%s",Map[i]+1);
rep(j,1,m){
if(Map[i][j]=='S')s={i,j};
if(Map[i][j]=='T')t={i,j};
}
}
bfs(s,dis1,link1);
bfs(t,DoubleFind::val,link2);
DoubleFind::init();
// puts("");
// rep(i,1,n)rep(j,1,m){
// printf("%d%c",dis1[i][j]," \n"[j==m]);
// }
// puts("");
// rep(i,1,n)rep(j,1,m){
// printf("%d%c",DoubleFind::val[i][j]," \n"[j==m]);
// }
// puts("");
// rep(i,1,n+d)rep(j,1,m+d){
// printf("%d%c",DoubleFind::Min[i][j]," \n"[j==m+d]);
// }
// puts("");
// rep(i,1,n+d)rep(j,1,m+d){
// printf("(%d,%d)%c",DoubleFind::Ans[i][j].fi,DoubleFind::Ans[i][j].se," \n"[j==m+d]);
// }
int ans=2e9;
pill SS,TT;
rep(i,1,n)rep(j,1,m){
if(Map[i][j]!='X'){
int V=dis1[i][j]+1+DoubleFind::Findval(i+d,j+d);
if(V<ans){
ans=V;
SS={i,j};
TT=DoubleFind::Ans[i+d][j+d];
}
}
}
int ans1=2e9;
pill PP;
rep(i,1,n)rep(j,1,m){
if(Map[i][j]!='X'){
int V=dis1[i][j]+DoubleFind::val[i][j];
if(V<ans1){
ans1=V;
PP={i,j};
}
}
}
if(ans1>1e8&&ans>1e8){
puts("-1");
return 0;
}
printf("%d\n",min(ans,ans1));
if(ans1<ans){
SS=PP;
TT=PP;
}
stack<pill>sta;
bool same=(SS==TT);
do{
sta.push(SS);
if(SS==s)break;
SS=link1[SS.fi][SS.se];
}while(1);
while(!sta.empty()){
printf("%d %d\n",sta.top().fi-1,sta.top().se-1);
sta.pop();
}
if(!same){
printf("%d %d\n",TT.fi-1,TT.se-1);
}
if(TT==t)return 0;
TT=link2[TT.fi][TT.se];
while(1){
printf("%d %d\n",TT.fi-1,TT.se-1);
if(TT==t)return 0;
TT=link2[TT.fi][TT.se];
}
return 0;
}