1. 程式人生 > 其它 >牛的旅行(資訊學奧賽一本通 - T1343)

牛的旅行(資訊學奧賽一本通 - T1343)

技術標籤:資訊學奧賽一本通(第五版)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;
}