[USACO09JAN] 最佳牧场 S
题目链接:https://www.luogu.com.cn/problem/P2935
题目描述
贝茜,总是希望优化她的生活,她发现自己真的很喜欢访问农夫约翰的P (1 <= P <= 500)个牧场中的F (1 <= F <= P)个她最喜欢的牧场F_i。
贝茜知道她可以通过C (1 <= C <= 8,000)条双向的牛道(方便地编号为1…C)来连接各个牧场,以便在整个农场的任何牧场之间旅行。每条路径P_i都有一个时间T_i (1 <= T_i <= 892)来穿越该路径(无论哪个方向)和两个路径端点a_i和b_i (1 <= a_i <= P; 1 <= b_i <= P)。
贝茜想找到最好的牧场来睡觉,这样当她醒来时,到达她的F个最喜欢的牧场的平均时间就最小了。
举例来说,考虑一个农场的布局如下图所示,其中*'d牧场编号是最喜欢的。括号中的数字是穿越牛道的时间。
1*--[4]--2--[2]--3
| |
[3] [4]
| |
4--[3]--5--[1]---6---[6]---7--[7]--8*
| | | |
[3] [2] [1] [3]
| | | |
13* 9--[3]--10*--[1]--11*--[3]--12*
以下表格显示了牧场4、5、6、7、9、10、11和12的潜在’最佳位置’的距离:
* * * * * * 最喜欢的 * * * * * *
潜在的最佳 牧场 牧场 牧场 牧场 牧场 牧场 平均
牧场 1 8 10 11 12 13 距离
------------ -- -- -- -- -- -- -----------
4 7 16 5 6 9 3 46/6 = 7.67
5 10 13 2 3 6 6 40/6 = 6.67
6 11 12 1 2 5 7 38/6 = 6.33
7 16 7 4 3 6 12 48/6 = 8.00
9 12 14 3 4 7 8 48/6 = 8.00
10 12 11 0 1 4 8 36/6 = 6.00 ** 最佳
11 13 10 1 0 3 9 36/6 = 6.00
12 16 13 4 3 0 12 48/6 = 8.00
因此,假设这些选择是最好的(一个程序必须以某种方式检查所有的选择),最好的睡觉地点是牧场10。
约翰拥有P(1<=P<=500)个牧场.贝茜特别喜欢其中的F个.所有的牧场 由C(1 < C<=8000)条双向路连接,第i路连接着ai,bi,需要Ti(1<=Ti< 892)单 位时间来通过.
作为一只总想优化自己生活方式的奶牛,贝茜喜欢自己某一天醒来,到达所有那F个她喜欢的 牧场的平均需时最小.那她前一天应该睡在哪个牧场呢?请帮助贝茜找到这个最佳牧场.
此可见,牧场10到所有贝茜喜欢的牧场的平均距离最小,为最佳牧场.
输入格式
* 第1行:三个空格分隔的整数:P、F和C
* 第2行到F+1行:第i+2行包含一个整数:F_i
* 第F+2行到C+F+1行:第i+F+1行用三个空格分隔的整数描述牛道i:a_i、b_i和T_i
输出格式
* 第1行:一行,一个整数,表示最好的牧场在哪里睡觉。如果有多个牧场是最好的,选择最小的那个。
样例 #1
样例输入 #1
13 6 15
11
13
10
12
8
1
2 4 3
7 11 3
10 11 1
4 13 3
9 10 3
2 3 2
3 5 4
5 9 2
6 7 6
5 6 1
1 2 4
4 5 3
11 12 3
6 10 1
7 8 7
样例输出 #1
10
提示
如题目所述
如题目所述。
思路解析
用 F l o y d Floyd Floyd 算法将多源最短路算出多源点的最短路距离,最后加起来比较即可。
CODE
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int, int> pii;
const int N = 520, M = 8010;
int d[N][N]; // 存储每个节点之间的最短距离
int n, m, k; // n是节点数,k是喜欢的节点数,m是边的数目
vector<int> love; // 存储喜欢的节点
// Floyd-Warshall算法,用于计算所有节点对之间的最短路径
void floyd(){
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] == INF || d[k][j] == INF) ? INF : d[i][k] + d[k][j]);
}
int main(){
cin >> n >> k >> m; // 输入节点数,喜欢的节点数,边的数目
// 初始化距离矩阵
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
d[i][j] = (i == j ? 0 : INF);
// 输入喜欢的节点
while(k--){
int f;
scanf("%d", &f);
love.push_back(f);
}
// 输入边的信息
while(m--){
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
d[a][b] = d[b][a] = min(d[a][b], w);
}
// 计算所有节点对之间的最短路径
floyd();
int ans = 0, res = INF; // 初始化答案和最小平均距离
// 遍历所有节点,找到平均距离最小的节点
for(int i = 1; i <= n; ++i){
int tmp = 0;
for(int j = 0; j < love.size(); ++j){
tmp += d[i][love[j]];
}
if(res > tmp){
res = tmp;
ans = i;
}
}
cout << ans; // 输出结果
}
- 唯一需要注意的点就是
res
要初始化成一个很大的数,不然会影响后续记录最小的点