这道题个人觉得很恶心,看了题解发现原来有这么好的方法。。。
一开始用并查集分组,后来发现虽然分组后思路清晰,但很复杂啊!
于是,发现了一种好方法(下次要好好琢磨题目啊):
大体思路是先贮存所有的路径,再用Floyd-Warshall算法,简单来说就是一下算出每对点之间的最短路径,至于具体的内容自己百度。
然后用一个zuiduan数组贮存在未连通时有这个点的最大直径。
再一一枚举每条可以连的路,再判断zuiduan。(这里很神奇的是,连通两个点之后,这个新图形的直径(这里有个要求,这个直径必须经过原来两个图形)就是两个点各自的zuiduan之和再加上这条新加的路径)
选出最小的直径。
再与原先单个图形时的直径进行比较,选出最大的(原先的是必经过两个原图形的,可是也有可能一个原图形的直径就比我们假象的直径要大,也就是那个一个图形的直径才是直径)
最后提醒一下,题目说不要四舍五入,其实是要的。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <iomanip>
using namespace std;
struct aaaa{int x;int y;}s[155];
int n;
double map[155][155],zuiduan[155];
int main()
{
freopen("cowtour.in","r",stdin);
freopen("cowtour.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
{cin>>s[i].x>>s[i].y;
zuiduan[i]=0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
char a;
cin>>a;
if(a=='1'){
map[i][j]=sqrt((s[i].x-s[j].x)*(s[i].x-s[j].x)+(s[i].y-s[j].y)*(s[i].y-s[j].y));
}
else map[i][j]=999999999;
if(i==j)map[i][j]=0;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(map[i][j]>map[i][k]+map[k][j]){
map[i][j]=map[i][k]+map[j][k];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(map[i][j]!=999999999&&map[i][j]>zuiduan[i])
zuiduan[i]=map[i][j];
}
double aa=999999999;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(map[i][j]==999999999){
if(aa>zuiduan[i]+zuiduan[j]+sqrt((s[i].x-s[j].x)*(s[i].x-s[j].x)+(s[i].y-s[j].y)*(s[i].y-s[j].y)))
aa=zuiduan[i]+zuiduan[j]+sqrt((s[i].x-s[j].x)*(s[i].x-s[j].x)+(s[i].y-s[j].y)*(s[i].y-s[j].y));
}
}
for (int i=1;i<=n;i++)
if (zuiduan[i]>aa) aa=zuiduan[i];
cout<<setprecision(6)<<fixed;
cout<<aa<<endl;
return 0;
}