牛的旅行(信息学奥赛一本通 - T1343)

题目描述
农民 John 的农场里有很多牧区,有的路径连接一些特定的牧区,一片所有连通的牧区称为一个牧场。

但是就目前而言,你能看到至少有两个牧区不连通,现在,John想在农场里添加一条路径 ( 注意,恰好一条 )。

对这条路径有这样的限制:一个牧场的直径就是牧场中最远的两个牧区的最短距离。

考虑如下的两个牧场,图1是有 5 个牧区的牧场,牧区用 “*” 表示,路径用直线表示,每一个牧区都有自己的坐标:

图1所示的牧场的直径大约是 12.07106,最远的两个牧区是 A 和 E,它们之间的最短路径是 A-B-E。
在这里插入图片描述

这两个牧场都在 John 的农场上,

John 将会在两个牧场中各选一个牧区,然后用一条路径连起来,使得连通后这个新的更大的牧场有最小的直径。

注意,如果两条路径中途相交,我们不认为它们是连通的,只有两条路径在同一个牧区相交,我们才认为它们是连通的。

现在请你编程找出一条连接两个不同牧场的路径,使得连上这条路径后,这个更大的新牧场有最小的直径。

输入格式
第 1 行:一个整数 N , 表示牧区数;
第 2 到 N + 1 行:每行两个整数 X,Y, 表示 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

输入数据中至少包括两个不连通的牧区。

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

输入样例
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

输出样例
22.071068

数据范围
1 ≤ N ≤ 150
0 ≤ X, Y ≤ 105


题解
Floyd:

解题步骤

  1. 先做一遍 Floyd,求出每个点所能达到的最远距离 MAX_len[i],并找出牧场的最大直径 R
  2. 遍历所有不连通的点,若 i、j 不连通,则连线后所能达到的最远距离为 MAX_len[i] + get_distance(i, j) + MAX_len(j);
  3. 由于连线后的距离可能小于原来牧场的最大直径,因此要对 R连线后的距离最小值max
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

typedef pair<int, int> PII;

const int N = 160;
const double INF = 0x3f3f3f3f;

int n;
PII q[N];
double d[N][N], MAX_len[N];
char g[N][N];

double get_distance(int a, int b)
{
    
    
    int dx = q[a].first - q[b].first;
    int dy = q[a].second - q[b].second;
    return sqrt(dx * dx + dy * dy);
}

int main()
{
    
    
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> q[i].first >> q[i].second;
    for (int i = 1; i <= n; i ++) cin >> g[i] + 1;
    
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= n; j ++)
            if(i != j)
            {
    
    
                if(g[i][j] == '1') d[i][j] = get_distance(i, j);
                else d[i][j] = INF;
            }
            
    for (int k = 1; k <= n; k ++)
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= n; j ++)
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
          
    double R = 0;            
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= n; j ++)
            if(d[i][j] != INF)
            {
    
    
                MAX_len[i] = max(MAX_len[i], d[i][j]);
                R = max(R, MAX_len[i]);    
            }
                
    double ans = INF;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= n; j ++)
            if(d[i][j] == INF)
                ans = min(ans, get_distance(i, j) + MAX_len[i] + MAX_len[j]);
                
    printf("%.6f", max(R, ans));            
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_46239370/article/details/113837311
今日推荐