先上一波题目 https://www.luogu.org/problem/P1522
这道题其实就是给你几个相互独立的连通图
问找一条新的路把其中的两个连通图连接起来后使得新的图中距离最远的两个点之间的距离最小
当然这里不同点之间的距离都取最短的距离
那么我们可以预处理一波 每个独立的连通图里面最远的两个点的距离是多少
可以利用并查集维护哪些点是在同一个连通图中的
然后每一个点单独跑一遍最短路 然后就可以处理出每个独立的连通图的‘直径’了
然后再暴力枚举新的边(i,j) 新形成的图的直径就是两个单独图的直径的最大值
或者是经过新的边连接的另外两个最远点的距离 即离i最远的点的距离加上离j最远的点的距离加上边(i,j)的值
这样问题就顺利解决了 算法的复杂度应该就是n^3logn
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #define inf 1e9+7 using namespace std; const int M=207; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,x[M],y[M],s[M][M]; int first[M],cnt; struct node{int to,next; double w;}e[M*M]; void ins(int x,int y,double w){ e[++cnt]=(node){y,first[x],w}; first[x]=cnt; //printf("%d %d %.2lf\n",x,y,w); } double gd(int a,int b){return sqrt(1.0*(x[a]-x[b])*(x[a]-x[b])+1.0*(y[a]-y[b])*(y[a]-y[b]));} int fa[M]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} double dis[M][M],ans=inf,mxd[M]; struct qwq{ int id; double d; bool operator<(const qwq&x)const{return x.d<d;} }; priority_queue<qwq>q; void dj(int S){ dis[S][S]=0; q.push((qwq){S,dis[S][S]}); while(!q.empty()){ qwq x=q.top(); q.pop(); if(x.d>dis[S][x.id]) continue; for(int i=first[x.id];i;i=e[i].next){ int now=e[i].to; if(dis[S][now]>dis[S][x.id]+e[i].w){ dis[S][now]=dis[S][x.id]+e[i].w; q.push((qwq){now,dis[S][now]}); } } } mxd[S]=0; for(int i=1;i<=n;i++) if(dis[S][i]!=inf) mxd[S]=max(mxd[S],dis[S][i]); } int col[M],sum; double dd[M]; int main(){ n=read(); for(int i=1;i<=n;i++) x[i]=read(),y[i]=read(),fa[i]=i; for(int i=1;i<=n;i++){ int c=getchar(); while(c!='0'&&c!='1') c=getchar(); for(int j=1;j<=n;j++){ s[i][j]=(c-'0'); dis[i][j]=(double)inf; if(s[i][j]){ ins(i,j,gd(i,j)); int p=find(i),q=find(j); if(p!=q) fa[p]=q; } c=getchar(); } } for(int i=1;i<=n;i++) dj(i); for(int i=1;i<=n;i++){ int p=find(i); if(!col[p]) col[p]=++sum; col[i]=col[p]; dd[col[i]]=max(dd[col[i]],mxd[i]); } //for(int i=1;i<=n;i++) printf("%d ",col[i]); puts("qwq"); //printf("%.2lf %.2lf\n",dd[1],dd[2]); //for(int i=1;i<=n;i++) printf("%.2lf ",mxd[i]); puts("qwq"); for(int i=1;i<=n;i++){ int p=find(i); for(int j=i+1;j<=n;j++){ int q=find(j); if(p!=q){ double d1=max(dd[col[p]],dd[col[q]]); double d2=max(d1,mxd[i]+mxd[j]+gd(i,j)); ans=min(ans,d2); } } } printf("%.6lf\n",ans); return 0; }