这道题需要用到图的遍历的知识,首先需要判断连通片,然后进行Floyd算法求每个连通片的最短路径,然后将每个点的最大值保存起来,又因为只有一条路径,所以我们只需要将任意两个不同连通片的点连接起来并进行判断是否是最小即可。代码如下。
#include<bits/stdc++.h>
#define INF 0xfffffff
using namespace std;
int o[200][200],n=0,visit[200],maxn[10];;
double oi[200][200],m[200],mm=INF,ansn[40000];
struct nam{
int x;
int y;
}point[200];
int se (int x,int c){
for (int k=1;k<=c;k++){
if (maxn[k]>=x){
return k;
}
}
}
void get (int x,int y){
int xx=0,yy=0;
xx=point[x].x-point[y].x;
yy=point[x].y-point[y].y;
oi[x][y]=sqrt(xx*xx+yy*yy);
}
void exchange (int x,int cnt){
visit[x]=1;
for (int j=1;j<=n;j++){
if (o[x][j]==-1){
o[x][j]=cnt;
if (!visit[j]){
if (j>maxn[cnt]){
maxn[cnt]=j;
}
exchange(j,cnt);
}
}
}
}
int main (){
freopen ("cowtour.in","r",stdin);
freopen ("cowtour.out","w",stdout);
cin>>n;
int cnt=1;
for (int i=1;i<=n;i++){
int ii=0,jj=0;
cin>>ii>>jj;
point[cnt].x=ii;
point[cnt++].y=jj;
}
string s;
bool flag = false;
for (int i=1;i<=n;i++){
cin>>s;
for (int j=1;j<=n;j++){
o[i][j]=s[j-1]-'0';
if (o[i][j]){
o[i][j]=-1;
flag=true;
}
}
}
if (!flag){
mm=1;
printf ("%.6f\n",mm);
return 0;
}
cnt=0;
while (maxn[cnt]<n){
exchange(maxn[cnt]+1,cnt+1);
cnt++;
}
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (o[i][j]!=0){
get(i,j);
}
}
}
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (oi[i][j]==0){
oi[i][j]=INF;
}
}
}
int ct=cnt;
while (ct!=0){
for (int k=1;k<=n;k++){
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if ((oi[i][j]>(oi[i][k]+oi[k][j]))
){
if (i==j){
continue;
}
oi[i][j]=oi[i][k]+oi[k][j];
}
}
}
}
ct--;
}
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (oi[i][j]>m[i]&&oi[i][j]!=INF){
m[i]=oi[i][j];
}
}
}
if (cnt==1){
mm=0;
for (int i=1;i<=n;i++){
if (m[i]>mm){
mm=m[i];
}
}
printf ("%.6f\n",mm);
return 0;
}
int c=1;
ct=1;
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (se(i,cnt)==se(j,cnt)){
continue;
}
int xx=0,yy=0;
xx=point[i].x-point[j].x;
yy=point[i].y-point[j].y;
ansn[c]=m[i]+m[j]+sqrt(xx*xx+yy*yy);
c++;
}
ct--;
}
for (int i=1;i<=(c-1);i++){
if (ansn[i]<mm){
mm=ansn[i];
}
}
printf ("%.6f\n",mm);
return 0;
}