题目描述(抽象模型)
农夫约翰要把他的牛奶运输到各个销售点。
运输过程中,可以先把牛奶运输到一些销售点,再由这些销售点分别运输到其他销售点。
运输的总距离越小,运输的成本也就越低。
低成本的运输是农夫约翰所希望的。
不过,他并不想让他的竞争对手知道他具体的运输方案,所以他希望采用费用第二小的运输方案而不是最小的。
现在请你帮忙找到该运输方案。
注意:
- 如果两个方案至少有一条边不同,则我们认为是不同方案;
- 费用第二小的方案在数值上一定要严格小于费用最小的方案;
- 答案保证一定有解;
输入格式
第一行是两个整数 N,M,表示销售点数和交通线路数;
接下来 M 行每行 3 个整数 x,y,z,表示销售点 x 和销售点 y 之间存在线路,长度为 z。
输出范围
输出费用第二小的运输方案的运输总距离。
数据范围
1 ≤ N ≤ 500,
1 ≤ M ≤ 104,
1 ≤ z≤ 109,
数据中可能包含重边。
输入样例
4 4
1 2 100
2 4 200
2 3 250
3 4 100
输出样例
450
算法思路
- 由一定存在次小生成树一定与最小生成树有一条边不同这个性质
- 先用kruskal求出最小生成树
- 求出每个两个点之间距离的最大值和次大值
- 遍历所有不在树中的边,若边权大于该边两点路径上边的最大值,则用该边取代最大的边,并更新答案,若边权等于该边两点路径上的最大值,则用该边取代次大边,并更新答案,由于是最小生成树,所以不存在该边小于最大边的情况
- 输出答案
AC代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510, M = 10010;
typedef long long LL;
int n, m, p[N], dist1[N][N], dist2[N][N];
struct node {
int a, b, w;
bool flag;
}edge[M];
int h[N], e[N * 2], ne[N * 2], w[N * 2], idx;
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
bool cmp(node a, node b)
{
return a.w < b.w;
}
int find(int x)
{
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
void dfs(int u, int fa, int maxd1, int maxd2, int d1[], int d2[])
{
d1[u] = maxd1, d2[u] = maxd2;
for(int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if(j != fa)
{
int t1= maxd1, t2 = maxd2;
if(w[i] > t1) t2 = t1, t1 = w[i];
else if(w[i] < t1 && w[i] > t2) t2 = w[i];
dfs(j, u, t1, t2, d1, d2);
}
}
}
int main(void)
{
cin >> n >> m;
memset(h, -1, sizeof(h));
for(int i = 0; i < m; i++)
{
int a, b, w;
cin >> a >> b >> w;
edge[i] = {a, b, w};
}
sort(edge, edge + m, cmp);
for(int i = 1; i <= n; i++) p[i] = i;
LL sum = 0;
for(int i = 0; i < m; i++)
{
int a = edge[i].a, b = edge[i].b, w = edge[i].w;
int pa = find(a), pb = find(b);
if(pa != pb)
{
p[pa] = pb;
sum += w;
add(a, b, w), add(b, a, w);
edge[i].flag = true;
}
}
for(int i = 1; i <= n; i++) dfs(i, -1, 0, 0, dist1[i], dist2[i]);
LL res = 1e18;
for(int i = 0; i < m; i++)
{
if(!edge[i].flag)
{
int a = edge[i].a, b = edge[i].b, w = edge[i].w;
if(w > dist1[a][b])
{
res = min(res, sum + w - dist1[a][b]);
}
else res = min(res, sum + w - dist2[a][b]);
}
}
cout << res << endl;
return 0;
}
本文探讨了农夫约翰的牛奶运输问题,旨在找到费用第二小的运输方案。通过使用Kruskal算法求解最小生成树,并结合边的次大权重,确定次小生成树。算法思路包括先构建最小生成树,然后遍历所有边,替换能减少总费用的边,最终输出次小的运输总距离。
1334

被折叠的 条评论
为什么被折叠?



