来源:http://ace.delos.com/usacoprob2?a=ecro6SKAJN4&S=cowtour
看到题目的数据范围就知道这题应该用O(n^3)的算法做了,明显图论中Floyd算法就符合要求。
算法:
1.floyd求出任意两点的距离;
2.对于连通块A和连通块B,添加一条边e(u,v),把A和B联通,新的连通块称为C,则:
dist[C]=dist[A][u]+dist[B][v]+e(u,v) //dist[C]表示连通块C的最大距离,dist[A][u]表示连通块A中的点离u点的最远距离
3.枚举边e(u,v),找出最小的最大距离
具体的程序如下:
/* ID:ay27272 PROG:cowtour LANG:C++ */ #include <iostream> #include <cstdio> #include <cstring> #include <string> #include <math.h> using namespace std; #define MINN 0.0001 struct node{ int x,y; node() { x=y=0; } node(int a,int b) { x=a; y=b; } }; double a[155][155]; struct node d[155]; int n; double sqrtt(int a,int b) //求出两点的距离 { double x1=d[a].x-d[b].x; double x2=d[a].y-d[b].y; return sqrt(x1*x1+x2*x2); } void floyd() { for (int k=1;k<=n;k++) //floyd算法模板 for (int i=1;i<=n;i++) if (i!=k) for (int j=1;j<=n;j++) if (i!=j && k!=j) if (a[i][k]>MINN && a[k][j]>MINN && (a[i][j]-a[i][k]-a[k][j]>MINN || a[i][j]<MINN)) a[i][j]=a[i][k]+a[k][j]; for (int i=1;i<=n;i++) //记录每个点在其连通块中与其它点的最大距离 for (int j=1;j<=n;j++) if (a[i][0]<a[i][j]) a[i][0]=a[i][j]; } int main() { freopen("cowtour.in","r",stdin); freopen("cowtour.out","w",stdout); int xx,yy; scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d%d\n",&xx,&yy); d[i]=node(xx,yy); } char s[200]; for (int i=1;i<=n;i++) { gets(s); for (int j=0;j<n;j++) { if (s[j]=='0') a[i][j+1]=a[j+1][i]=0.0; else a[i][j+1]=a[j+1][i]=sqrtt(i,j+1); } } floyd(); double maxx=10000000.0,k; for (int i=1;i<=n;i++) //枚举边e(i,j) for (int j=1;j<=n;j++) if (i!=j) { k=sqrtt(i,j)+a[i][0]+a[j][0]; if (a[i][j]<MINN && k<maxx) maxx=k; } for (int i=1;i<=n;i++) //这一步不能省,因为有可能添加边后最大的距离并不在这个新的连通块中 maxx=max(maxx,a[i][0]); printf("%.6lf\n",maxx); return 0; }