USACO Cow Tours

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);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值