Gym 101617D
题意:
有一个nXn的图,由.和#组成,现在从1,1出发,每次跳最多k个格子,落点不能是#,问到(n,n)最少需要几步,如果无法到达则输出-1.注意只能向右和下走。
思路:
直接bfs查询会超时,因为2000的数据会存很多点,但是如果对能到达的格子快速查找最小的步数可以用高级数据结构来完成,线段树。
- 对于每一行和每一列用线段树维护
#include <iostream>
#include <cstdio>
#include <math.h>
#include <cstring>
using namespace std;
const int maxn = 2005;
const int inf = 0x3f3f3f3f;
int n,k;
char s[maxn][maxn];
int ans[maxn][maxn];
struct Node
{
int d[maxn<<2];
void build(int rt,int l,int r) {
d[rt] = inf;
if(l == r) return ;
int mid = (r+l)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
}
void update(int rt,int l,int r,int x,int v) {
if(l == r) {
d[rt] = min(d[rt],v);
return ;
}
int mid = (l+r)>>1;
if(mid >= x) update(rt<<1,l,mid,x,v);
else update(rt<<1|1,mid+1,r,x,v);
d[rt] = min(d[rt<<1],d[rt<<1|1]);
}
int query(int rt,int l,int r,int L,int R) {
if(l >= L && r <= R) {
return d[rt];
}
int ans = inf;
int mid = (l+r)>>1;
if(mid >= R) return query(rt<<1,l,mid,L,R);
else if(mid < L) return query(rt<<1|1,mid+1,r,L,R);
else {
ans = query(rt<<1,l,mid,L,R);
ans = min(ans,query(rt<<1|1,mid+1,r,L,R));
}
return ans;
}
}treei[maxn],treej[maxn];
int main()
{
freopen("in.txt","r",stdin);
scanf("%d%d",&n,&k);
for(int i = 1;i <= n; i++) {
scanf("%s",s[i]+1);
}
memset(ans,inf,sizeof(ans));
ans[1][1] = 0;
for(int i = 1;i <= n; i++) {
treei[i].build(1,1,n);
treej[i].build(1,1,n);
}
treei[1].update(1,1,n,1,0);
treej[1].update(1,1,n,1,0);
for(int i = 1;i <= n; i++) {
for(int j = 1;j <= n; j++) {
if(i == 1 && j == 1) continue;
if(s[i][j] == '.') {
int l,r,anstemp;
anstemp = inf;
l = max(1,i-k),r = max(1,i-1);
anstemp = min(anstemp,treej[j].query(1,1,n,l,r)+1);
l = max(1,j-k),r = max(1,j-1);
anstemp = min(anstemp,treei[i].query(1,1,n,l,r)+1);
treej[j].update(1,1,n,i,anstemp);
treei[i].update(1,1,n,j,anstemp);
ans[i][j] = anstemp;
}
}
}
if(ans[n][n] == inf) printf("-1\n");
else printf("%d\n",ans[n][n]);
return 0;
}