题目链接:https://codeforces.com/contest/1343/problem/E
想法:
我们可以考虑假设一个重复点D (D可以和 A、B、C重合) ,那么我们的问题就转化为 A->D->B->D->C (类似于样例一)
然后我们分别跑三次最短路,然后取枚举 D 就行了。 需要注意一下就是如果此时边的个数 > m 的时候肯定是走了重复的路的,是不符合条件的
其余的情况 贪心就好了
#pragma GCC optimize(3, "Ofast", "inline")//O3优化 #pragma GCC optimize(2)//O2优化 #include <algorithm> #include <string> #include <cstring> #include <vector> #include <map> #include <stack> #include <set> #include <queue> #include <cmath> #include <cstdio> #include <iomanip> #include <ctime> #include <bitset> #include <cmath> #include <sstream> #include <iostream> #define ll long long #define ls nod<<1 #define rs (nod<<1)+1 #define pii pair<int,int> #define mp make_pair #define pb push_back #define INF 0x3f3f3f3f3f3f3f3f #define max(a, b) (a>b?a:b) #define min(a, b) (a<b?a:b) #define int ll const double eps = 1e-10; const int maxn = 4e5 + 10; const int MOD = 998244353; int sgn(double a) { return a < -eps ? -1 : a < eps ? 0 : 1; } using namespace std; int w[maxn]; int head[maxn]; int vis[maxn]; int dis_a[maxn],dis_b[maxn],dis_c[maxn]; int cnt = 0; int sum[maxn]; struct edge{ int to,nxt,val; }e[maxn]; void add_edge(int u,int v) { e[cnt].to = v; e[cnt].val = 1; e[cnt].nxt = head[u]; head[u] = cnt++; } void dijstra_a(int s) { priority_queue<pii,vector<pii>,greater<pii> > q; dis_a[s] = 0; q.push({dis_a[s],s}); while (!q.empty()) { int now = q.top().second; q.pop(); if (vis[now]) continue; vis[now] = true; for (int i = head[now];~i;i = e[i].nxt) { int v = e[i].to; if (dis_a[v] > dis_a[now] + e[i].val) { dis_a[v] = dis_a[now] + e[i].val; q.push({dis_a[v],v}); } } } } void dijstra_b(int s) { priority_queue<pii,vector<pii>,greater<pii> > q; dis_b[s] = 0; q.push({dis_b[s],s}); while (!q.empty()) { int now = q.top().second; q.pop(); if (vis[now]) continue; vis[now] = true; for (int i = head[now];~i;i = e[i].nxt) { int v = e[i].to; if (dis_b[v] > dis_b[now] + e[i].val) { dis_b[v] = dis_b[now] + e[i].val; q.push({dis_b[v],v}); } } } } void dijstra_c(int s) { priority_queue<pii,vector<pii>,greater<pii> > q; dis_c[s] = 0; q.push({dis_c[s],s}); while (!q.empty()) { int now = q.top().second; q.pop(); if (vis[now]) continue; vis[now] = true; for (int i = head[now];~i;i = e[i].nxt) { int v = e[i].to; if (dis_c[v] > dis_c[now] + e[i].val) { dis_c[v] = dis_c[now] + e[i].val; q.push({dis_c[v],v}); } } } } signed main() { ios::sync_with_stdio(false); int t; cin >> t; while (t--) { cnt = 0; memset(head,-1,sizeof(head)); int n,m,a,b,c; cin >> n >> m >> a >> b >> c; for (int i = 1;i <= m;i++) { cin >> w[i]; } sort(w+1,w+1+m); for (int i = 1;i <= m;i++) { sum[i] = sum[i-1] + w[i]; } for (int i = 1;i <= m;i++) { int u,v; cin >> u >> v; add_edge(u,v); add_edge(v,u); } for (int i = 1;i <= n;i++) { vis[i] = 0; dis_a[i] = dis_b[i] = dis_c[i] = INF; } dijstra_a(a); for (int i = 1;i <= n;i++) vis[i] = 0; dijstra_b(b); for (int i = 1;i <= n;i++) vis[i] = 0; dijstra_c(c); int ans = INF; for (int i = 1;i <= n;i++) { int disa_i = dis_a[i]; int disb_i = dis_b[i]; int disc_i = dis_c[i]; if (disa_i + disb_i + disc_i > m) continue; ans = min(ans,sum[disa_i + disb_i + disc_i] + sum[disb_i]); } cout << ans << endl; } return 0; }
原文:https://www.cnblogs.com/-Ackerman/p/13177446.html