1343E - Weights Distributing
题意:给定连通图(无重边和自环),共m条边,每条边的价格确定,重新排列每条边的价格,使得从a到b再到c的价格最小
显然路径边数越小,可以使得价格最小。所以我们需要确定a——> b——> c的路径中,边数最小一条路径。
贪心的想,只有两种情况
1.a -> b -> c
2.中间有一个转折点:a -> x -> b -> x -> c
可以看成一种情况,即a -> x -> b -> x -> c
所以我们只需要枚举每一个x取最小值,所以现在我们需要处理出a, b, c到图上任一点的最小边数,做三次dijkstra即可
此题得到解决:
从终点出发,我们已经找到了某条路径使得其价格最小,因为其边数确定,所以我们可以肯定,这些边的价格一定是最小的价格。
所以我们得到特征:目标路径每条边依次取最小价格边,从而为了得到终点,我们应该是的目标路径边数最少
所以核心特征:从a->b->c的最少边数路径即为目标路径
然后我们思考如何得到最少边数路径,特征:路径必定存在一个转折点x,使得a->b, b->c均经过x,所以我们枚举x即可
点击查看代码
#include<bits/stdc++.h>
using i64 = long long;
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t; std::cin >> t;
while(t--){
int n, m, a, b, c;
std::cin >> n >> m >> a >> b >> c;
--a, --b, --c;
std::vector<i64> p(m);
for(int i = 0; i < m; ++i){
std::cin >> p[i];
}
std::sort(p.begin(), p.end());
std::vector<i64> sum(m + 1);
for(int i = 0; i < m; ++i){
sum[i + 1] = sum[i] + p[i];
}
std::vector<int> e[n];
for(int i = 0; i < m; ++i){
int u, v; std::cin >> u >> v;
--u, --v;
e[u].push_back(v);
e[v].push_back(u);
}
auto dijkstra = [&](int s){
std::vector<int> d(n, -1);
std::queue<int> q;
d[s] = 0; q.push(s);
while(!q.empty()){
int u = q.front(); q.pop();
for(auto v : e[u]){
if(d[v] == -1){
d[v] = d[u] + 1;
q.push(v);
}
}
}
return d;
};
auto d1 = dijkstra(a), d2 = dijkstra(b), d3 = dijkstra(c);
i64 ans = (i64)1e18;
for(int i = 0; i < n; ++i){
if(d1[i] + d2[i] + d3[i] > m){
continue;
}
ans = std::min(ans, sum[d2[i]] + sum[d1[i] + d2[i] + d3[i]]);
}
std::cout << ans << '\n';
}
return 0;
}
浙公网安备 33010602011771号