1. 程式人生 > 實用技巧 >codeforces-1343E(貪心+BFS)

codeforces-1343E(貪心+BFS)

Weights Distributing

題目連結:https://codeforces.com/contest/1343/problem/E

題目描述:

給定n個點m條無向邊,再給你a,b,c三個點和m個值,現在要求你將這m個值分配這m條邊,使a->b->c的路徑的權值最小

思路:

分類討論,一種情況是a->b和b->c這兩條路上無交點,這樣直接將權值排序後取最小即可,第二種就是兩條路上有交點,這時候我們一定可以找到一個交點x,該交點把路徑分為a->x,x->b,b->x,x->c這四段路線,因為b->x和x->b本質上是同一條路,所以我們需要優先把較小的權值分配給這條路,可以先用bfs求出a、b、c三個點到所有點的單位距離,接著貪心賦值即可。

程式碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 0x3f3f3f3f;
const ll N = 1e6;
const double PI = acos(-1.0);
#define Test ll tesnum;tesnum = read();while(tesnum--)
ll read();
ll val[N];
vector<int> g[N];
void bfs(int id,vector<int> &v)
{
    v[id] = 0;
    queue<int> q;
    q.push(id);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        for(int nx:g[u]){
            if(v[nx]==INF){
                v[nx] = v[u]+1;
                q.push(nx);
            }
        }
    }
}
int main()
{
    Test{
        int n,m,a,b,c;
        cin>>n>>m>>a>>b>>c;
        for(int i = 1; i <= m; i++){
            cin>>val[i];
        }
        for(int i = 1; i <= n; i++)g[i].clear();
        sort(val+1,val+1+m);
        for(int i = 1; i <= m; i++){
            int u,v;
            cin>>u>>v;
            g[u].push_back(v);
            g[v].push_back(u);
            val[i] += val[i-1];
        }
        vector<int> disa(n+1,INF);
        vector<int> disb(n+1,INF);
        vector<int> disc(n+1,INF);
        bfs(a,disa);
        bfs(b,disb);
        bfs(c,disc);
        ll ans  = 2e16;
        for(int i = 1; i <= n; i++){
            if(disa[i]+disb[i]+disc[i]>m)continue;
            ans = min(ans,val[disb[i]]+val[disa[i]+disb[i]+disc[i]]);
        }
        cout<<ans<<endl;
    };
    return "BT7274", NULL;
}

inline ll read() {
    ll hcy = 0, dia = 1;char boluo = getchar();
    while (!isdigit(boluo)) {if (boluo == '-')dia = -1;boluo = getchar();}
    while (isdigit(boluo)) {hcy = hcy * 10 + boluo - '0';boluo = getchar();}
    return hcy * dia;
}