BZOJ3161 : 孤舟蓑笠翁

显然求出每个点到所有关键点的最短路和次短路即可,答案就是每个关键点的次短路。

设$f[i][j][0]$表示左手在$i$,右手在$j$的解,$f[i][j][1]$表示左手在$i$,右手在$j$,且左手已经动了右手还没开始动的解,然后BFS即可。

时间复杂度$O(n(n+m))$。

 

#include<cstdio>
const int N=1010,M=10010;
int n,m,K,dmi,dma,i,j,k,x,y,z,vip[N][N],ans[N*N],e[2][N],v[M],nxt[M],ed,h,t,q[N*N*4][5];
struct P{int x,y;P(){}P(int _x,int _y){x=_x,y=_y;}}a[N],f[N][N][2],g[N][N][2];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int&x,int y){v[++ed]=y;nxt[ed]=x;x=ed;}
inline int abs(int x){return x>0?x:-x;}
inline bool check(int x,int y){
  int d=abs(a[x].x-a[y].x)+abs(a[x].y-a[y].y);
  return dmi<=d&&d<=dma;
}
inline void ext(int x,int y,int z,int a,int b){
  if(!z&&!check(x,y))return;
  if(g[x][y][z].y)return;
  if(f[x][y][z].y==b)return;
  q[++t][0]=x,q[t][1]=y,q[t][2]=z,q[t][3]=a,q[t][4]=b;
  if(!f[x][y][z].y)f[x][y][z]=P(a,b);else g[x][y][z]=P(a,b);
}
int main(){
  read(n),read(m),read(dmi),read(dma);
  for(i=1;i<=n;i++)read(a[i].x),read(a[i].y);
  read(K);
  for(i=1;i<=K;i++)read(x),read(y),vip[x][y]=i;
  while(m--){
    read(x),read(y),read(z);
    add(e[z][x],y),add(e[z][y],x);
  }
  for(i=1;i<=n;i++)add(e[0][i],i),add(e[1][i],i);
  for(h=i=1;i<=n;i++)for(j=1;j<=n;j++)if(vip[i][j])ext(i,j,0,0,vip[i][j]);
  while(h<=t){
    x=q[h][0],y=q[h][1],z=q[h][2],j=q[h][3]+1-z,k=q[h++][4];
    for(i=e[z][z?y:x];i;i=nxt[i])ext(z?x:v[i],z?v[i]:y,z^1,j,k);
  }
  for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(vip[i][j])ans[vip[i][j]]=g[i][j][0].y?g[i][j][0].x:-1;
  for(i=1;i<=K;i++)printf("%d\n",ans[i]);
  return 0;
}

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值