题目
农夫约翰要把他的牛奶运输到各个销售点。
运输过程中,可以先把牛奶运输到一些销售点,再由这些销售点分别运输到其他销售点。
运输的总距离越小,运输的成本也就越低。
低成本的运输是农夫约翰所希望的。
不过,他并不想让他的竞争对手知道他具体的运输方案,所以他希望采用费用第二小的运输方案而不是最小的。
现在请你帮忙找到该运输方案。
注意::
- 如果两个方案至少有一条边不同,则我们认为是不同方案;
- 费用第二小的方案在数值上一定要严格大于费用最小的方案;
- 答案保证一定有解;
输入格式
第一行是两个整数 N,M,表示销售点数和交通线路数;
接下来 M 行每行 3 个整数 x,y,z,表示销售点 x 和销售点 y 之间存在线路,长度为 z。
输出格式
输出费用第二小的运输方案的运输总距离。
数据范围
1≤N≤5e2
1≤M≤1e4
1≤z≤1e9
数据中可能包含重边。
输入样例:
4 4
1 2 100
2 4 200
2 3 250
3 4 100
输出样例:
450
思路
第一步:生成最小生成树,使用邻接表储存起来,并且标记树边。
第二部:找到最小生成树中点 i 到点 j 中间经过的最大边与次大边。
第三步:遍历非树边,若加进去某非树边,整个最小生成树的变化
样例演示
先按照步骤一生成最小生成树,并标记树边,如下图
红色的为最小生成树的树边。
然后进行第二步找到点 i 到点 j 的最大值与次大值。
最后进行第三步,遍历所有非树边,观察加进去某一条边,最小生成树的变化。
比如加入图中的黑色边,2到3的最大边为200,小于250,将边 2-4改为2-3,最小生成树就变为次小生成树,权值变为450。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,pair<int,int>> PII;
const int N = 5e2 + 10,M = 1e4 + 10;
int n,m;
int p[N];
struct Edge{
int x,y,w;
bool f;
bool operator < (const Edge& A) const{
return w < A.w;
}
}edge[M];
int h[N],ne[N * 2],e[N * 2],w[N * 2],idx;
int dist1[N][N],dist2[N][N];
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void add(int a,int b,int c)
{
ne[idx] = h[a],e[idx] = b,w[idx] = c,h[a] = idx ++;
}
void dfs(int u,int fa,int maxx1,int maxx2,int d1[],int d2[])
{
d1[u] = maxx1;
d2[u] = maxx2;
for(int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
int m1 = maxx1,m2 = maxx2;
if(j == fa) continue;
if(w[i] > m1) m2 = m1,m1 = w[i];
else if(w[i] > m2 && w[i] < m1) m2 = w[i];
dfs(j,u,m1,m2,d1,d2);
}
}
int32_t main()
{
cin >> n >> m;
memset(h,-1,sizeof h);
for(int i = 1; i <= n; i ++) p[i] = i;
for(int i = 0; i < m; i ++) cin >> edge[i].x >> edge[i].y >> edge[i].w;
sort(edge,edge + m);
int ans = 0;
for(int i = 0; i < m; i ++)
{
int x = find(edge[i].x);
int y = find(edge[i].y);
int d = edge[i].w;
if(x == y) continue;
ans += d;
p[x] = y;
edge[i].f = true;
add(edge[i].x,edge[i].y,d);
add(edge[i].y,edge[i].x,d);
}
for(int i = 1; i <= n; i ++) dfs(i,-1,-1e9,-1e9,dist1[i],dist2[i]);
int len = 1e18;
for(int i = 0; i < m; i ++)
{
if(edge[i].f) continue;
int d = edge[i].w;
int x = edge[i].x;
int y = edge[i].y;
if(d > dist1[x][y]) len = min(len,d - dist1[x][y]);
else if(d > dist2[x][y]) len = min(len,d - dist2[x][y]);
}
cout << ans + len << endl;
return 0;
}
难度:中等 |
时/空限制:1s / 64MB |
总通过数:5868 |
总尝试数:16709 |
来源:《信息学奥赛一本通》 , USACO |
算法标签 |
题目来自: 1148. 秘密的牛奶运输 - AcWing题库