[关闭]
@himnouth 2022-08-08T06:56:31.000000Z 字数 1575 阅读 323

题解

Atcoder Beginner Contest 259 Problem D 题解

题目链接:https://atcoder.jp/contests/abc259/tasks/abc259_d

题目大意

现给定个在平面坐标系中的圆,第个圆圆心坐标为,半径为。又给定两个坐标,试求出可否从出发且只经过给定圆的圆周可否到达点

输入格式

对于每个测试点,第一行输入,第二行输入,其后行,每行输入

输出格式

如果能到达,输出"";否则输出""。

样例输入1

  1. 4
  2. 0 -2 3 3
  3. 0 0 2
  4. 2 0 2
  5. 2 3 1
  6. -3 3 3

样例输出1

  1. Yes

样例输入2

  1. 3
  2. 0 1 0 3
  3. 0 0 1
  4. 0 0 2
  5. 0 0 3

样例输出2

  1. No

样例解释1

原图如下:

以下为从点至点的走法之一。
1. 从点经过给定的第一个圆可移动到点
2. 从点经过给定的第二个圆可移动到点
3. 从点经过给定的第三个圆可移动到点

样例解释2

原图如下:

由图可知:
不可在只经过圆周的情况下从点移动至点

解析

本题使用图论算法求解。
可将所有圆编号并视为一个点,若两个圆可相互到达,即可视为两点间存在一条边,以样例为例,则原图可化为一无向图,如下:

原问题可变化为:求点与点是否联通。
以上问题可使用深度优先搜索算法进行求解。
综上,原问题解法为:先将原图转化为有向图后使用深度优先搜索算法判断起点与终点是否连通即可。

代码实现

以上算法代码实现如下:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. using ll=long long;
  4. ll b,k,sx,sy,gx,gy;
  5. ll ask(){
  6. ll ans=k*(abs(sx-gx)+abs(sy-gy));
  7. ll sy_2=sy-sy%b,gy_2=gy-gy%b,sx_2=sx-sx%b,gx_2=gx-gx%b;
  8. for(auto [x_1,y_1]:{array{sx,sy_2},{sx,sy_2+b},{sx_2+b,sy},{sx_2,sy}}){
  9. for(auto [x_2,y_2]:{array{gx,gy_2},{gx,gy_2+b},{gx_2+b,gy},{gx_2,gy}}){
  10. ll res;
  11. if(x_1%b==0&&x_2%b==0&&y_1/b==y_2/b){
  12. int r=y_2%b+y_1%b;
  13. res=min((ll)abs(y_2-y_1)+(ll)abs(x_2-x_1)*k,(ll)min(abs(x_2-x_1)+r,(ll)abs(x_2-x_1)+2*b-r));
  14. }
  15. else if(y_1%b==0&&y_2%b==0&&x_1/b==x_2/b){
  16. int r=x_2%b+x_1%b;
  17. res=min((ll)abs(x_2-x_1)+(ll)abs(y_2-y_1)*k,(ll)min(abs(y_2-y_1)+r,(ll)abs(y_2-y_1)+2*b-r));
  18. }
  19. else{
  20. res=(ll)abs(x_2-x_1)+(ll)abs(y_2-y_1);
  21. }
  22. res+=k*(abs(x_1-sx)+abs(y_1-sy)+abs(x_2-gx)+abs(y_2-gy));
  23. ans=min(ans,res);
  24. }
  25. }
  26. return ans;
  27. }
  28. int main(){
  29. int T;
  30. cin>>T;
  31. while(T--){
  32. scanf("%lld%lld%lld%lld%lld%lld",&b,&k,&sx,&sy,&gx,&gy);
  33. printf("%lld\n",ask());
  34. }
  35. return 0;
  36. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注