Codeforces Round #636 (Div. 3)

题目链接

http://codeforces.com/contest/1343/problem/E

tag

最短路,贪心,思维

solution

给定边权集合,给无向图的每条边赋值,使得从a->b->c的最小花费最少
有两种情况 :

  1. a到b,b到c不经过同一条边两次
  2. a到b,b到c需经过同一条边两次
    两种情况均可以表示成:设x为可达到a,b,c的点,cost可以表示为dis(a,x) + 2 * dis(b,x)+dic(c,x)
    首先置所有的边权为1,bfs算出a,b,c到每个点的最短路,我们至少要走dis(a,x) + dis(b, x) + dis(c,x)条边,另外dis(b,x)条边走了两次,所以贪心的分配边权的话这条边应该分配给最小的dis(b,x)个边权给这条路径,我们可以将边权排序,做一个前缀和,cost=presum[dis(a,x) + dis(b, x) + dis(c,x)] + pre[dis(b, x)],需要保证dis(a,x) + dis(b, x) + dis(c,x) <= m,因为最多只有m条边

code

//created by pyoxiao on 2020/07/08
#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define CL(a, b) memset(a, b, sizeof(a))
using namespace std;
const int mod = 1e9 + 7;
LL fpow(LL a, LL b, LL p = mod){LL ans = 1; a %= p; while(b) {if(b & 1) ans = ans * a % p; b >>= 1; a = a * a % p;} return ans;}
LL gcd(LL a, LL b){return b == 0 ? a : gcd(b, a % b);}
const int N = 2e5 + 7;
int n, m, a, b, c;
bool v[N];
LL da[N], db[N], dc[N], p[N], pre[N];
vector<int> ver[N];
queue<int> q;
void solve() {
    scanf("%d %d %d %d %d", &n, &m, &a, &b, &c);
    for(int i = 0; i <= n; i ++) da[i] = db[i] = dc[i] = 1e18, ver[i].clear();
    for(int i = 1; i <= m; i ++) scanf("%lld", &p[i]);
    sort(p + 1, p + m + 1); pre[0] = 0;
    for(int i = 1; i <= m; i ++) pre[i] = pre[i - 1] + p[i];
    for(int i = 1; i <= m; i ++) {
        int u, v;
        scanf("%d %d", &u, &v);
        ver[u].pb(v);
        ver[v].pb(u);
    }
    while(q.size()) q.pop();
    q.push(a); 
    da[a] = 0;
    while(q.size()) {
        int x = q.front(); q.pop();
        for(auto to : ver[x]) {
            if(da[to] == 1e18) {
                da[to] = da[x] + 1;
                q.push(to); 
            }
        }
    }
    while(q.size()) q.pop();
    q.push(b); 
    db[b] = 0;
    while(q.size()) {
        int x = q.front(); q.pop();
        for(auto to : ver[x]) {
            if(db[to] == 1e18) {
                db[to] = db[x] + 1;
                q.push(to); 
            }
        }
    }
    while(q.size()) q.pop();
    q.push(c); 
    dc[c] = 0;
    while(q.size()) {
        int x = q.front(); q.pop();
        for(auto to : ver[x]) {
            if(dc[to] == 1e18) {
                dc[to] = dc[x] + 1;
                q.push(to); 
            }
        }
    }
    LL ans = LONG_LONG_MAX;
    for(int i = 1; i <= n; i ++) {
        if(da[i] + db[i] + dc[i] <= m) {
            //LL cur = ans;
            ans = min(ans, pre[da[i] + db[i] + dc[i]] + pre[db[i]]);

            //cout << i << ' ' << ans << '
';
        }
    }
    printf("%lld
", ans);
}
int main() {
    int T = 1;
    scanf("%d", &T);
    while(T --) 
        solve();
    return 0;
}
原文地址:https://www.cnblogs.com/pyoxiao/p/13270100.html