题目:
思路:
题目要求的是加上一条边,连接两个连通块之后,形成的新连通块的最小直径。
A连通块与B连通块连接后形成的新连通块的最小直径有三种情况:
1.A连通块的直径
2.B连通块的直径
3.d[i]+d[j]+getdis(i,j)
并查集用于分成不同的几个连通块
最短路(floyd)用于寻找多源最短路,连通块里点与点直接的“距离”
d[i]用于存储i所在的连通块里,与i所在的最长直径
a数组用来储存一个连通块里的最长直径
AC代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
using namespace std;
const int maxn=211;
int n,fa[maxn];
char s[maxn];
double f[maxn][maxn],d[maxn],a[maxn];
struct point
{
double x,y;
}p[maxn];
int getfa(int x)
{
return (x==fa[x])?x:(fa[x]=getfa(fa[x]));
}
void merge(int x,int y)
{
int xx=getfa(x),yy=getfa(y);
if (xx==yy) return;
fa[yy]=xx;
}
double getdis(int i,int j)
{
return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
}
void floyd()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
}
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
f[i][j]=0x3f3f3f3f;
}
}
for(int i=1;i<=n;i++)
{
cin>>s;
for(int j=1;j<=n;j++)
{
if(s[j-1]=='1')
{
merge(i,j);
double temp=getdis(i,j);
f[i][j]=temp;
f[j][i]=temp;
//cout<<temp<<endl;
}
}
}
for(int i=1;i<=n;i++) f[i][i]=0;
floyd();
/*for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cout<<"i="<<i<<" "<<"j="<<j<<" "<<f[i][j]<<endl;
}
}*/
double ans=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(f[i][j]!=0x3f3f3f3f)
{
//cout<<"i="<<i<<" "<<"j="<<j<<" "<<endl;
d[i]=max(d[i],f[i][j]);
//cout<<<"d[i]="<<d[i]<<" ";
//a[fa[i]]=max(a[fa[i]],d[i]);
//cout<<"i="<<i<<" "<<"d[i]="<<d[i]<<" "<<"a[fa[i]]="<<a[fa[i]]<<endl;
}
}
}
//for(int i=1;i<=n;i++) cout<<"i="<<i<<" "<<"d[i]="<<d[i]<<endl;
for(int i=1;i<=n;i++)
{
a[getfa(i)]=max(a[getfa(i)],d[i]);
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(getfa(i)!=getfa(j))
{
double temp=max(d[i]+d[j]+getdis(i,j),max(a[fa[i]],a[fa[j]]));
ans=min(ans,temp);
}
}
}
printf("%.6lf\n",ans);
return 0;
}