[关闭]
@AkamemakA 2022-06-29T02:34:30.000000Z 字数 1828 阅读 189

题解 Atcoder

Atcoder Beginner Contest 257 problem D 题解


题目链接:点我

题目大意

有N张蹦床,每张蹦床i在的位置有一个属性值;一个人本身有一个属性值。定义两蹦床之间的距离为:


一个人在蹦床能够跳到蹦床,当且仅当满足:

求一个最小的,使得一个人从某一蹦床出发,能够到达所有蹦床。


样例输入1

  1. 4
  2. -10 0 1
  3. 0 0 5
  4. 10 0 1
  5. 11 0 1

样例输出1

  1. 2

样例解释1

时,不存在一张蹦床,使得从此开始可以跳到所有蹦床。
时,他可以从号蹦床开始,跳到所有蹦床。
例如,他跳到号蹦床可以用如下操作:

样例输入2

  1. 7
  2. 20 31 1
  3. 13 4 3
  4. -10 -15 2
  5. 34 26 5
  6. -2 39 4
  7. 0 -50 1
  8. 5 -20 2

样例输出2

  1. 18

数据范围


解析

这道题当然可以暴力解决。
从小到大枚举,对每一个,枚举每一个点,看从此点能否遍历到每一个点,时间复杂度。(亲测,还是能过几个点的(doge))

不过,这种暴力解法却给我们提供了一些思路。

那么如何去快速判断能否从某一个点到达其他所有点呢?

于是问题得到简化。对于每两个点,如果从能够到达,则这个图上从有一条边。

用邻接矩阵存储这个图,最后直接用Floyd算法即可直接判断是否连通。

需要注意的是,能够从走到并不意味着能够从走到,也就是说,这个图不是双向的。不能算出一向,就定了另一向。还有就是要注意数据范围,亲测不开


代码实现

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=205;
  4. #define int long long //超级懒狗
  5. int n;
  6. int x[N],y[N],p[N];
  7. int a[N][N]; //a[i][j]表示从i到j的距离
  8. bool b[N][N]; //邻接矩阵
  9. inline bool check(int mid){
  10. memset(b,0,sizeof b); //多次check,需要初始化
  11. for(int i=1;i<=n;i++)
  12. for(int j=1;j<=n;j++)
  13. if(i!=j)
  14. b[i][j]=(p[i]*mid>=a[i][j]); //若i能到j,则b[i][j]=1;否则为0。
  15. for(int k=1;k<=n;k++)
  16. for(int i=1;i<=n;i++)
  17. for(int j=1;j<=n;j++)
  18. if(i!=j&&j!=k&&i!=k)
  19. b[i][j]|=b[i][k]&b[k][j]; //Floyd模板
  20. for(int i=1;i<=n;i++){
  21. bool g=1;
  22. for(int j=1;j<=n;j++)
  23. if(b[i][j]==0&&i!=j) g=0;
  24. if(g) return 1;
  25. } //枚举每个点,看从此点能否到达其他所有点,即是否b[i]中除第i个数以外的元素都为1
  26. return 0;
  27. }
  28. signed main() //signed超懒型
  29. {
  30. cin>>n;
  31. for(int i=1;i<=n;i++){
  32. scanf("%lld%lld%lld",&x[i],&y[i],&p[i]);
  33. for(int j=1;j<i;j++)
  34. a[i][j]=a[j][i]=abs(x[i]-x[j])+abs(y[i]-y[j]); //计算距离
  35. }
  36. int l=0,r=1e10,ans=0;
  37. while(l<=r){
  38. int mid=(l+r)/2;//long long间不能使用位运算
  39. if(check(mid)) r=mid-1,ans=mid;
  40. else l=mid+1;
  41. } //二分模板(注意l与r的取值)
  42. cout<<ans;
  43. return 0;
  44. }

完结撒花~

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注