【题解】这道题,我想写一下我的整个思路:
首先,我题目没有了解清楚(痛),觉得可能是最小生成树。后来仔细看题目发现是求一段连通图中的最远的两个点的距离,可以用Floyd 求新的图的距离,但怎么考虑连接两个牧场呢,要保证时间效率过得去。然后我突然想到可以向处理出每一个牧场中的相互距离,最后连接就是把各个牧场到连接点的距离求出+那两个点连接的距离,即边(v1,v2),v1 牧场到v1的距离+v2牧场到v2的距离+dis(v1,v2);去一个最小值就是答案。然后我交上去,发现在第7个点的时候WA了,由于数据太大,实在没法调,我看了一下题解(没有自己仔仔细细地思考算法是否存在问题,是个严重的失误),突然醒悟,就是没有考虑到单个牧场中的直径。最后就A了。
/*
ID:CYMXYYM1
TASK:cowtour
LANG:C++
*/
#include<cstdio>
#include<cstring>
#include<cmath>
#define DB double
#define inf 1047483641.0
int tot=0,w[500],xz[500],yz[500],next[500];
int f[500][500],s[500],twice[500],n;
DB d[500][500],from[500];
void dfs(int x)
{
twice[x]=1;w[x]=tot;
for(int i=1;i<=n;i++)
if((!twice[i]) && (f[x][i]))
{
next[i]=s[tot];s[tot]=i;dfs(i);
}
}
inline void dis(int x)
{
for(int i=s[x];i;i=next[i])
for(int j=s[x];j;j=next[j])
for(int k=s[x];k;k=next[k])
if(d[j][k]>d[j][i]+d[i][k])d[j][k]=d[j][i]+d[i][k];
}
//平方;
inline DB fang(DB p){return p*p;}
//求直接距离;
inline DB getdis(int xx,int yy){
return sqrt(fang((DB)xz[yy]-xz[xx])+fang((DB)yz[yy]-yz[xx]));
}
inline DB max(DB x,DB y){return x>y?x:y;}
inline DB min(DB x,DB y){return x<y?x:y;}
int main()
{
freopen("cowtour.in","r",stdin);
freopen("cowtour.out","w",stdout);
char ch;scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&xz[i],&yz[i]);
for(int i=1;i<=n;i++)
{
while(ch=getchar(),ch=='\n' || ch=='\r');
for(int j=1;j<=n;j++)f[i][j]=(int)ch-48,ch=getchar();
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j)d[i][j]=0;else d[i][j]=inf;
memset(twice,0,sizeof(twice));
memset(s,0,sizeof(s));
memset(from,0,sizeof(from));
for(int i=1;i<=n;i++)
if(!twice[i])
{
tot++;s[tot]=i;next[i]=0;dfs(i);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(f[i][j])d[i][j]=getdis(i,j);
for(int i=1;i<=tot;i++)dis(i);
for(int i=1;i<=tot;i++)
for(int j=s[i];j;j=next[j])
for(int k=s[i];k;k=next[k])
if(d[j][k]>from[i])from[i]=d[j][k];
DB minx=inf;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(w[i]!=w[j]){
DB max1=0,max2=0;
for(int k=s[w[i]];k;k=next[k])
if(k!=i)max1=max(max1,d[k][i]);
for(int k=s[w[j]];k;k=next[k])
if(k!=j)max2=max(max2,d[k][j]);
minx=min(minx,max(max(from[w[i]],from[w[j]]),max1+max2+getdis(i,j)));
}
printf("%.6lf\n",minx);
return 0;
}