题目描述
农夫约翰要把他的牛奶运输到各个销售点。
运输过程中,可以先把牛奶运输到一些销售点,再由这些销售点分别运输到其他销售点。
运输的总距离越小,运输的成本也就越低。
低成本的运输是农夫约翰所希望的。
不过,他并不想让他的竞争对手知道他具体的运输方案,所以他希望采用费用第二小的运输方案而不是最小的。
现在请你帮忙找到该运输方案。
注意:
如果两个方案至少有一条边不同,则我们认为是不同方案;
费用第二小的方案在数值上一定要严格小于费用最小的方案;
答案保证一定有解;
输入格式
第一行是两个整数 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
思路
- 我们先求出最小生成树
- 把树建成图, 然后进行树的遍历, 存下a->b这条边的最大边权和严格次大边权
- 最后我们遍历每一条题目中给出的边, 如果这条边没有在树中, 同时它又比这条边上的最大权值大, 就替换掉最大权值,如果比次大权值大, 就替换掉次大权值
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510, M = 10010;
int f[N];
struct node{
int x, y, dis;
bool is_tree;
bool operator<(const node &a) const
{
return dis < a.dis;
}
}ed[M];
int n, m;
int dis[N][N], dis2[N][N];
int e[M], w[M], ne[M], h[N], len;
void add(int a, int b, int c)
{
e[len] = b;
w[len] = c;
ne[len] = h[a];
h[a] = len++;
}
void init()
{
for(int i = 0; i < N; i++)
f[i] = i;
}
int find(int x)
{
if(f[x] == x)return x;
return f[x] = find(f[x]);
}
void dfs(int u, int fa, int maxd1, int maxd2, int dis1[], int dis2[])
{
dis1[u] = maxd1;
dis2[u] = maxd2;
for(int i = h[u]; ~i; i = ne[i])
{
int y = e[i];
if(y != fa)
{
// cout << u << " " << y << endl;
int td1 = maxd1, td2 = maxd2;
int c = w[i];
if(c > maxd1)
td2 = td1, td1 = c;
else if(c < maxd1 && c > maxd2)
td2 = c;
dfs(y, u, td1, td2, dis1, dis2);
}
}
}
int main()
{
cin >> n >> m;
init();
for(int i = 1; i <= m; i++)
{
int a, b, c;
cin >> a >> b >> c;
ed[i] = {a, b, c};
}
long long sum = 0;
memset(h, -1, sizeof h);
sort(ed + 1, ed + m + 1);
for(int i = 1; i <= m; i++)
{
int x = find(ed[i].x);
int y = find(ed[i].y);
if(x != y)
{
int a = ed[i].x;
int b = ed[i].y;
int z = ed[i].dis;
f[x] = y;
add(a, b, z);
add(b, a, z);
ed[i].is_tree = true;
sum += ed[i].dis;
}
else ed[i].is_tree = false;
}
for(int i = 1; i <= n; i++) dfs(i, -1, -1e9, -1e9, dis[i], dis2[i]);
long long ans = 1e18;
for(int i =1; i <= m; i++)
{
if(!ed[i].is_tree)
{
int z = ed[i].dis;
int a = ed[i].x;
int b = ed[i].y;
if(z > dis[a][b])
ans = min(ans, sum - dis[a][b] + z);
else if(z > dis2[a][b])
ans = min(ans, sum - dis2[a][b] + z);
}
}
cout << ans << endl;
return 0;
}