p1522 牛的旅行 Cow Tours
题目
农民 John的农场里有很多牧区。有的路径连接一些特定的牧区。一片所有连通的牧区称为一个牧场。但是就目前而言,你能看到至少有两个牧区通过任何路径都不连通。这样,Farmer John就有多个牧场了。输入文件包括牧区、它们各自的坐标,还有一个对称邻接矩阵。输入文件至少包括两个不连通的牧区。请编程找出一条连接两个不同牧场的路径,使得连上这条路径后,这个更大的新牧场有最小的直径。输出在所有牧场中最小的可能的直径。
输入格式:
第1行: 一个整数N (1 <= N <= 150), 表示牧区数
第2到N+1行: 每行两个整数X,Y (0 <= X ,Y<= 100000), 表示N个牧区的坐标。注意每个 牧区的坐标都是不一样的。
第N+2行到第2*N+1行: 每行包括N个数字(0或1) 表示如上文描述的对称邻接矩阵。
输出格式:
只有一行,包括一个实数,表示所求直径。数字保留六位小数。
只需要打到小数点后六位即可,不要做任何特别的四舍五入处理。
分析
以为n较小,所以我们可以用floyd求出任意联通两点的最短距离。然后我们就可以找到每个点在联通块中与其最远的点。我们枚举所有不连通的点,将这两个点连接,所得到的新的直径即为两点各自在原联通块的最大距离相加加两点间距离。注意新的直径可能没有原来的直径大。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const double inf=1e9+7;
double x[1100],y[1100],dmax[110000],d[1100][1100];
double len(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 n,m,i,j,k;
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++){
if(i!=j)d[i][j]=inf;
char s;
cin>>s;
if(s=='1'){
d[i][j]=len(i,j);
}
}
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
for(i=1;i<=n;i++)dmax[i]=0;
double ans2=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(d[i][j]<inf){
dmax[i]=max(dmax[i],d[i][j]);
ans2=max(ans2,dmax[i]);
}
double ans=inf;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j)
if(d[i][j]>=inf){
ans=min(ans,dmax[i]+dmax[j]+len(i,j));
}
printf("%0.6lf",max(ans,ans2));
return 0;
}