蒟蒻の小窝(floyed:洛谷p1522)

本篇博客是我搬运自己洛谷上投的这题的题解,只不过没有被官方发布。
其实我已经有三篇题解是已经被展示啦(得意
今天夜晚刚颓废完,想给自己的C++系列填个坑。这道题虽然是蓝题,但我感觉可以划到橙题蒟蒻言论
下面就是完全ctrl cv自己的博客内容啦!
从拿到这道题到AC它,花了三小时。。。太蒻了
蒟蒻自闭了
蒟蒻也是开始学的floyd算法,题解各位犇犇已经给出了大致过程,所以蒟蒻想向
还没学floyd的犇犇们普及一下这种算法,我们先由floyd是个什么东西说起~
Floyed-Warshall算法 O(N^3)
简称Floyed(弗洛伊德)算法,是最简单的最短路径算法,可以计算图中任意两点
间的最短路径。Floyed的时间复杂度是O (N3),适用于出现负边权的情况。
以下没有特别说明的话,dis[u][v]表示从u到v最短路径长度,w[u][v]表示连
接u,v的边的长度。
算法描述:
初始化:点u、v如果有边相连,则dis[u][v]=w[u][v]。如果不相连则
dis[u]
[v]=0x7fffffff

For (k = 1; k <= n; k++)
    For (i = 1; i <= n; i++)
     For (j = 1; j <= n; j++)
         If (dis[i][j] >dis[i][k] + dis[k][j])
             dis[i][j] = dis[i][k] + dis[k][j];

算法结束:dis[i][j]得出的就是从i到j的最短路径。
算法分析&思想讲解:
三层循环,第一层循环中间点k,第二第三层循环起点终点i、j,算法的思想
很容易理解:如果点i到点k的距离加上点k到点j的距离小于原先点i到点j的距
离,那么就用这个更短的路径长度来更新原先点i到点j的距离。
  
在上图中,因为dis[1][3]+dis[3][2]<dis[1][2],所以就用dis[1]
[3]+dis[3][2]来更新原先1到2的距离。
  
 我们在初始化时,把不相连的点之间的距离设为一个很大的数,不妨可以
看作这两点相隔很远很远,如果两者之间有最短路径的话,就会更新成最短路
径的长度。Floyed算法的时间复杂度是O(N3)。
Floyed算法变形:
如果是一个没有边权的图,把相连的两点间的距离设为dis[i][j]=true,不
相连的两点设为dis[i][j]=false,用Floyed算法的变形:

For (k = 1; k <= n; k++)
  For (i = 1; i <= n; i++)
    For (j = 1; j <= n; j++)
    dis[i][j] = dis[i][j] || (dis[i][k] && dis[k][j]);

最后再强调一点:用来循环中间点的变量k必须放在最外面一层循环。

那么我们回到这题!

【算法分析】 用Floyed求出任两点间的最短路,然后求出每个点到所有可达的点的最大距离,记做mdis[i]。(Floyed算法)
  r1=max(mdis[i])
然后枚举不连通的两点i,j,把他们连通,则新的直径是
mdis[i]+mdis[j]+(i,j)间的距离。
 
r2=min(mdis[i]+mdis[j]+dis[i,j])
 
re=max(r1,r2)
 
re就是所求。

AC代码如下:

#include<bits/stdc++.h>
using namespace std;
double f[151][151],m[151],minx,r,temp,x[151],y[151],maxint=1e12;
double dist(int i,int j)
{
  return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])) ;  
}
int main()
{ int i,j,n,k;char c;
  cin>>n;
  for(i=1;i<=n;i++)cin>>x[i]>>y[i];
  for(i=1;i<=n;i++)
   for(j=1;j<=n;j++)
    { cin>>c;
      if(c=='1')f[i][j]=dist(i,j);
           else f[i][j]=maxint;
    }
  for(k=1;k<=n;k++)
    for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
        if(i!=j&&i!=k&&j!=k)
           if(f[i][k]<maxint-1&&f[k][j]<maxint-1)
              if(f[i][j]>f[i][k]+f[k][j])
                f[i][j]=f[i][k]+f[k][j];
   memset(m,0,sizeof(m));
   for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)
     if(f[i][j]<maxint-1&&m[i]<f[i][j])m[i]=f[i][j]; 
   minx=1e20;
  for(i=1;i<=n;i++)
   for(j=1;j<=n;j++)
    if(i!=j&&f[i][j]>maxint-1)
     {temp=dist(i,j);
      if(minx>m[i]+m[j]+temp)minx=m[i]+m[j]+temp;
     }
  r=0;
  for(i=1;i<=n;i++)if (m[i]>minx)minx=m[i];
  printf("%.6lf",minx);
  return 0;
}

这就是蒟蒻的题解了,如果对大家有用的话还请多多支持!

–2020.03.19 补全我的C++记忆。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值