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);
}
本文详细介绍了如何运用Floyd算法求解最短路径,并在代码实现中注意了两点是否处于同一连通块及直径定义的微妙之处。通过实例分析,深入探讨了算法的应用及优化。

643

被折叠的 条评论
为什么被折叠?



