WUST 1933 牛的旅行(超难理解的题意+Floyd)

针对一个复杂的图论问题——牛的旅行,通过弗洛伊德算法寻找最优路径以连接两个不连通的牧场,实现最小直径的目标。文章详细介绍了问题背景、解决思路及具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1933: 牛的旅行

Time Limit: 1 Sec   Memory Limit: 128 MB   64bit IO Format: %lld
Submitted: 16   Accepted: 7
[ Submit][ Status][ Web Board]

Description

  农民John的农场里有很多牧区。有的路径连接一些特定的牧区。一片所有连通的牧区称为一个牧场。但是就目前而言,你能看到至少有两个牧区不连通。现在,John想在农场里添加一条路径 ( 注意,恰好一条 )。对这条路径有这样的限制:一个牧场的直径就是牧场中最远的两个牧区的距离 ( 本题中所提到的所有距离指的都是最短的距离 )。
        每一个牧区都有自己的坐标。假如John的农场有2个牧场,第一个牧场有5个牧区A(10,10),B(15,10),C(20,10),D(15,15)和E(20,15)。第二个农场有3个牧区F(30,15),G(25,10)和H(30,10)。其中牧区A和B,牧区B和C,牧区B和D,牧区B和E,牧区C和E,牧区D和E,牧区F和G,牧区G和H均有路径连接。
   第一个牧场的直径大约是12.07106(最远的两个牧区是A和E,它们之间的最短路径是A-B-E)。
         John将会在两个牧场中各选一个牧区,然后用一条路径连起来,使得连通后这个新的更大的牧场有最小的直径。
         注意,如果两条路径中途相交,我们不认为它们是连通的。只有两条路径在同一个牧区相交,我们才认为它们是连通的。
         现在请你编程找出一条连接两个不同牧场的路径,使得连上这条路径后,这个更大的新牧场有最小的直径。

Input

包含多组测试数据。
第 1 行:一个整数N (1 <= N <= 150), 表示牧区数;
第 2 到 N+1 行:每行两个整数X,Y ( 0 <= X,Y<= 100000 ), 表示N个牧区的坐标。每个牧区的坐标都是不一样的。
第 N+2 行到第 2*N+1 行:每行包括N个数字 ( 0或1 ) 表示一个对称邻接矩阵。
例如,题目描述中的两个牧场的矩阵描述如下:
  A B C D E F G H      
A 0 1 0 0 0 0 0 0      
B 1 0 1 1 1 0 0 0      
C 0 1 0 0 1 0 0 0      
D 0 1 0 0 1 0 0 0      
E 0 1 1 1 0 0 0 0      
F 0 0 0 0 0 0 1 0      
G 0 0 0 0 0 1 0 1      
H 0 0 0 0 0 0 1 0   
输入数据中至少包括两个不连通的牧区。

Output

只有一行,包括一个实数,表示所求答案。数字保留六位小数。

Sample Input 

8
10 10
15 10
20 10
15 15
20 15
30 15
25 10
30 10
01000000
10111000
01001000
01001000
01110000
00000010
00000101
00000010


Sample Output

22.071068



[ Submit][ Status][ Web Board]
题解:

这题我居然做了一个小时。。。题目意思理解了好久,意思就是即使你用弗洛伊德求出每个点的最短路,也有几个点相互不连通,即长度为INF,然后你的任务是连通这些点然后求出连通后的最大直径中的最小的一个,由于原来里面就可能就存在最大直径,所以还要存一下原来所有点没连通之前的连通了的点的最大长度,然后在这些最大长度里面找最大值为直径,比较连通前后的最大直径,其中大的是答案

用代码语言就是先弗洛伊德搞一遍,然后遍历所有点,保存点到所有连通点的最大值a[i],在保存的这些点中的最大值中选最大的为r1,然后再把没连通的点连通,设没连通的点所为i,j,这时直径为a[i]+a[j]+dis[i,j],然后在这些直径中选一个最小的作为r2,然后答案就是max(r1,r2)

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<string>
#include<stdio.h>
#include<queue>
#include<stack>
#include<map>
#include<deque>
using namespace std;
const double INF=10086111;
double f[155][155];//保存各个点间的距离
double dx[155];//保存点的坐标
double dy[155];
double a[155];//保存每个点距离其他连通点的最大距离
int main()
{
    int i,j,k,n,ans,x;
    double maxx,t,r1,r2;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=0;i<n;i++)
        {
            scanf("%lf%lf",&dx[i],&dy[i]);
        }
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                scanf("%1d",&x);
                if(x)//连通就直接搞出距离
                {
                    t=sqrt((dx[i]-dx[j])*(dx[i]-dx[j])+(dy[i]-dy[j])*(dy[i]-dy[j]));
                    f[i][j]=t;
                }
                else
                    f[i][j]=INF;
            }
        }
        if(n==1)//去掉会错,只有一个点的情况
        {
            printf("%lf\n",0);
            continue;
        }
        else if(n==2)//只有两个点的情况
        {
            t=sqrt((dx[0]-dx[1])*(dx[0]-dx[1])+(dy[0]-dy[1])*(dy[0]-dy[1]));
            printf("%lf\n",t);
            continue;
        }
        for(k=0;k<n;k++)//弗洛伊德
        {
            for(i=0;i<n;i++)
            {
                for(j=0;j<n;j++)
                {
                    if(f[i][k]+f[k][j]<f[i][j])
                    {
                        f[i][j]=f[i][k]+f[k][j];
                    }
                }
            }
        }
        r1=0;
        for(i=0;i<n;i++)//找点与其他连通点的最大距离
        {
            a[i]=0;
            for(j=0;j<n;j++)
            {
                if(i==j)
                    continue;
                if(f[i][j]!=INF)
                {
                    if(a[i]<f[i][j])
                    {
                        a[i]=f[i][j];
                    }
                }
            }
            if(a[i]>r1)
                r1=a[i];
        }
        r2=INF;
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                if(i==j)//跳掉自己和自己连接
                    continue;
                if(f[i][j]==INF)//不连通
                {
                    t=sqrt((dx[i]-dx[j])*(dx[i]-dx[j])+(dy[i]-dy[j])*(dy[i]-dy[j]));
                    r2=min(r2,t+a[i]+a[j]);
                }
            }
        }
        maxx=max(r1,r2);
        printf("%lf\n",maxx);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值