1、拖了一天,终于靠着题解把这个题过掉了,so happy~
2、考察Floyd算法求最短路,其间要注意讨论两点是否在一个连通块。
3、要注意直径的定义,很微妙,不一定新形成的直径就大于原来的,因为新加的边的两端点可能不同于原来连通块的直径的点。
/*
ID:mrxy564
PROG:cowtour
LANG:C++
*/
#include<cstdio>
#include<cmath>
using namespace std;
struct point{
double x,y;
};
point a[155];
char G[155][155];
double d[155][155],dia[155];
const double INF=150000;
double dist(int i,int j){
double dx=a[i].x-a[j].x,dy=a[i].y-a[j].y;
double ans=sqrt(dx*dx+dy*dy);
return ans;
}
int main(){
freopen("cowtour.in","r",stdin);
freopen("cowtour.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lf%lf",&a[i].x,&a[i].y);
getchar();
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%c",&G[i][j]);
if(i==j){
d[i][j]=0;
}else if(G[i][j]=='1'){
d[i][j]=dist(i,j);
}else if(G[i][j]=='0'){
d[i][j]=INF;
}
}
getchar();
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(d[i][k]<INF&&d[k][j]<INF)
d[i][j]=d[i][j]<d[i][k]+d[k][j]?d[i][j]:d[i][k]+d[k][j];
for(int i=0;i<n;i++)
dia[i]=0;
double maxnum=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(fabs(d[i][j]-INF)<1e-9)
continue;
else{
dia[i]=dia[i]>d[i][j]?dia[i]:d[i][j];
if(dia[i]>maxnum) maxnum=dia[i];
}
double ans=INF;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(i==j||d[i][j]<INF) continue;
double temp=dist(i,j);
if(dia[i]+dia[j]+temp<ans)
ans=dia[i]+dia[j]+temp;
}
if(maxnum>ans) ans=maxnum;
printf("%.6lf\n",ans);
return 0;
}
官方题解:
We do a fair bit of precomputation before choosing the path to add.
First, we calculate the minimum distance between all connected points. Then, we use a recursive depth first search to identify the different fields. Then we fill in diam[i], which is defined to be the distance to the farthest pasture that pasture i is connected to. Fielddiam[j] is the diameter of field j, which is the maximum of diam[i] for all pastures i in the field j.
Once we have all this, selecting a path is simple. If we add a path joining pastures i and j which are in different fields, the diameter of the new field is the maximum of:
- dist to point farthest from i + dist from i to j + dist to point farthest from j.
- old diameter of the field containing pasture i.
- old diameter of the field containing pasture j.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <math.h> #define INF (1e40) typedef struct Point Point; struct Point { int x, y; }; #define MAXPASTURE 150 int n; double dist[MAXPASTURE][MAXPASTURE]; double diam[MAXPASTURE]; double fielddiam[MAXPASTURE]; Point pt[MAXPASTURE]; int field[MAXPASTURE]; int nfield; double ptdist(Point a, Point b) { return sqrt((double)(b.x-a.x)*(b.x-a.x)+(double)(b.y-a.y)*(b.y-a.y)); } /* mark the field containing pasture i with number m */ void mark(int i, int m) { int j; if(field[i] != -1) { assert(field[i] == m); return; } field[i] = m; for(j=0; j<n; j++) if(dist[i][j] < INF/2) mark(j, m); } void main(void) { FILE *fin, *fout; int i, j, k, c; double newdiam, d; fin = fopen("cowtour.in", "r"); fout = fopen("cowtour.out", "w"); assert(fin != NULL && fout != NULL); fscanf(fin, "%d\n", &n); for(i=0; i<n; i++) fscanf(fin, "%d %d\n", &pt[i].x, &pt[i].y); for(i=0; i<n; i++) { for(j=0; j<n; j++) { c = getc(fin); if(i == j) dist[i][j] = 0; else if(c == '0') dist[i][j] = INF; /* a lot */ else dist[i][j] = ptdist(pt[i], pt[j]); } assert(getc(fin) == '\n'); } /* Floyd-Warshall all pairs shortest paths */ for(k=0; k<n; k++) for(i=0; i<n; i++) for(j=0; j<n; j++) if(dist[i][k]+dist[k][j] < dist[i][j]) dist[i][j] = dist[i][k]+dist[k][j]; /* mark fields */ for(i=0; i<n; i++) field[i] = -1; for(i=0; i<n; i++) if(field[i] == -1) mark(i, nfield++); /* find worst diameters involving pasture i, and for whole field */ for(i=0; i<n; i++) { for(j=0; j<n; j++) if(diam[i] < dist[i][j] && dist[i][j] < INF/2) diam[i] = dist[i][j]; if(diam[i] > fielddiam[field[i]]) fielddiam[field[i]] = diam[i]; } /* consider a new path between i and j */ newdiam = INF; for(i=0; i<n; i++) for(j=0; j<n; j++) { if(field[i] == field[j]) continue; d = diam[i]+diam[j]+ptdist(pt[i], pt[j]); if(d < fielddiam[field[i]]) d = fielddiam[field[i]]; if(d < fielddiam[field[j]]) d = fielddiam[field[j]]; if(d < newdiam) newdiam = d; } fprintf(fout, "%.6lf\n", newdiam); exit(0); }