usaco Cow Tours

题意是给出一个不连通的图,然后定义了一个直径:联通分量里最短距离最长的两个点之间的距离。

求将一个不连通的图中的两个连通分量连接,生成的这个新分量的直径最小可以有多小,输出这个新直径。

做法是想用Floyd求出任意两点之间的最短距离,然后求出每个点到未生成新图之前的这个点所在分量的最远的一个点的距离。然后枚举联通两个不相连的两个点,这两个点的所在分量的最远距离,加上这两个点之间的距离,就是新生成的牧场的直径。

题目保证一定会有未联通的两个分量:

但是:这道题的第7个测试点我就是死活过不去,然后把这个数据分析了一下发现,这个测试点里的所有点都联通。

在此之前我还专门证明过,一个分量内部的直径一定小于两个分量相连之后新生成的分量的直径。结果题目这种测试数据和题目描述不一致坑的我什么都不想说了。

我就是想问一下人与人之间基本的信任呢

/*
ID: modengd1
PROG: cowtour
LANG: C++
*/
#include <iostream>
#include <stdio.h>
#include <memory.h>
#include <math.h>
#define INF 0xfffffff
using namespace std;
typedef pair<int,int> Coor;
double longestdist[151];
double A[151][151];
Coor coor[151];
bool con[151][151];
int N;
void Floyd()
{
    //求任意间接联通的两点之间的最短路径,并标记它们之间的间接联通关系
    for(int k=0;k<N;k++)
    {
        for(int i=0;i<N;i++)
        {
            if(A[i][k]!=INF&&k!=i)
            for(int j=0;j<N;j++)
            {
                if(A[k][j]!=INF&&k!=j)
                {
                    A[i][j]=min(A[i][j],A[i][k]+A[k][j]);
                    con[i][j]=true;
                }
            }
        }
    }
}
double dis(Coor A,Coor B)
{
    return sqrt((A.first-B.first)*(A.first-B.first)+(A.second-B.second)*(A.second-B.second));
}
void slove()
{
    double ans=INF;
    //找到每个节点所在分量中离这个节点最远的一个坐标的距离
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<N;j++)
        {
            if(con[i][j])
            {
                longestdist[i]=max(longestdist[i],A[i][j]);
            }
        }
    }
    //枚举任意两个不连通的点并且模拟将这两个点联通之后形成新牧场的直径
    for(int i=0;i<N-1;i++)
    {
        for(int j=1+i;j<N;j++)
        {
            if(!con[i][j])
            {
                ans=min(ans,longestdist[i]+longestdist[j]+dis(coor[i],coor[j]));
            }
        }
    }
    for(int i=0;i<N;i++)//处理假如数据已经全部连通了怎么办(题目强调一定有没连通的两个点,又碰见这种测试数据和题目描述不一样的我也是醉了
        ans=max(longestdist[i],ans);
    printf("%.6lf\n",ans);
}
int main()
{
    freopen("cowtour.in","r",stdin);
    freopen("cowtour.out","w",stdout);
    scanf("%d",&N);
    int a,b;
    char ch;
    for(int i=0;i<N;i++)
    {
        scanf("%d%d",&a,&b);
        coor[i].first=a;
        coor[i].second=b;
    }
    getchar();
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<N;j++)
        {
            scanf("%c",&ch);
            if(ch==‘0‘)//判断是否直接联通并且初始化用来Floyd的A数组
            {
                con[i][j]=false;
                A[i][j]=INF;
            }
            else
            {
                con[i][j]=true;
                A[i][j]=dis(coor[i],coor[j]);
            }
        }
        getchar();
        con[i][i]=true;//自己到自己一定是联通的且距离为0
        A[i][i]=0;
    }
    Floyd();
    slove();
    return 0;
}

  

时间: 2024-10-03 14:26:41

usaco Cow Tours的相关文章

USACO 2.4 Cow Tours

Cow Tours Farmer John has a number of pastures on his farm. Cow paths connect some pastures with certain other pastures, forming a field. But, at the present time, you can find at least two pastures that cannot be connected by any sequence of cow pat

【USACO 2.4】Cow Tours (最短路)

题意:给你n(最多150)个点的坐标,给出邻接矩阵,并且整个图至少两个联通块,现在让你连接一条边,使得所有可联通的两点的最短距离的最大值最小. 题解:先dfs染色,再用floyd跑出原图的直径O($n^3$),然后枚举新增的边的端点O($n^2$),再分别找出到边端点距离最远的点($n$),那么添加这条边后新图的直径要么是原图直径要么就是两个端点到各自最远点的距离之和加上边的长度.每次维护最小的直径.这样总的是O($n^3$). 代码: /* TASK:cowtour LANG:C++ */ #

Luogu P1522 牛的旅行 Cow Tours

题目描述 农民 John的农场里有很多牧区.有的路径连接一些特定的牧区.一片所有连通的牧区称为一个牧场.但是就目前而言,你能看到至少有两个牧区通过任何路径都不连通.这样,Farmer John就有多个牧场了. John想在牧场里添加一条路径(注意,恰好一条).对这条路径有以下限制: 一个牧场的直径就是牧场中最远的两个牧区的距离(本题中所提到的所有距离指的都是最短的距离).考虑如下的有5个牧区的牧场,牧区用“*”表示,路径用直线表示.每一个牧区都有自己的坐标: (15,15) (20,15) D

P1522 牛的旅行 Cow Tours

题目描述 农民 John的农场里有很多牧区.有的路径连接一些特定的牧区.一片所有连通的牧区称为一个牧场.但是就目前而言,你能看到至少有两个牧区通过任何路径都不连通.这样,Farmer John就有多个牧场了. John想在牧场里添加一条路径(注意,恰好一条).对这条路径有以下限制: 一个牧场的直径就是牧场中最远的两个牧区的距离(本题中所提到的所有距离指的都是最短的距离).考虑如下的有5个牧区的牧场,牧区用“*”表示,路径用直线表示.每一个牧区都有自己的坐标: (15,15) (20,15) D

usaco Cow Pedigrees

题意是,求N,个节点,组成高度为K的二叉树,形态有多少,且每个节点的度要么为0要么为2. 这题第一眼看后就知道要dp,但却没找到方程,看了别人题解之后才知道,原来是从分治的思想出发的. dp[i][j]的意思是用i个节点组成高度不超过j的二叉树的形态,那么dp[i][j]=dp[i][j]+dp[k][j-1]*dp[i-1-k][j-1],k=1,3,5..... 就是去掉根节点之后,求出左子树节点个数为k的形态数,乘上右子树节点个数为i-1-k时的形态数. 输出dp[N][K]-dp[N][

USACO Cow Pedigrees 【Dp】

一道经典Dp不过现在还不是能特别理解. 定义dp[i][j] 表示由i个节点,j 层高度的累计方法数 状态转移方程为: 用i个点组成深度最多为j的二叉树的方法树等于组成左子树的方法数 乘于组成右子树的方法数再累计. 暂贴代码: /* ID: wushuai2 PROG: nocows LANG: C++ */ //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h>

BZOJ 1629 Usaco Cow Acrobats

感觉就是一道贪心的题目,但是苦于没法下手.在瞎写了几组数据之后,猜了一个结论.A1-B1<A2-B2在看了看题解之后,发现自己好菜啊. 首先由两个前提条件 1. 两头牛调换顺序,并不会影响后面牛的计算. 2. 两头牛的顺序会影响答案. 所以 我们设 A,B为两个相邻的牛需要满足 Ax-By < Bx-Ay 的关系 才会使答案变小 #include <cstdio> #include <algorithm>   struct node{     long long  x,

USACO 2.4

USACO 2.4.1 题解: 模拟. 用一个6维数组储存农夫与奶牛当前状态是否出现过,若出现过则表明出现循环,直接输出0,f[农夫x][农夫y][农夫方向][奶牛x][奶牛y][奶牛方向]. 最后注意转弯要算一步. 代码: /* ID:m1599491 PROB:ttwo LANG:C++ */ #include<cmath> #include<cstdio> #include<cstring> #include<iostream> using names

3298: [USACO 2011Open]cow checkers

3298: [USACO 2011Open]cow checkers Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 65  Solved: 26[Submit][Status][Discuss] Description 一天,Besssie准备和FJ挑战奶牛跳棋游戏.这个游戏上在一个M*N(1<=M<=1,000,000;1<=N<=1,000,000)的棋盘上, 这个棋盘上在(x,y)(0<=x棋盘的左下角是(0,0)坐标,