제출 #1279752

#제출 시각아이디문제언어결과실행 시간메모리
1279752longdeptraiCities (BOI16_cities)C++20
22 / 100
101 ms3368 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = (ll)9e18;

struct Edge {
    int u, v;
    ll w;
};

struct DSU {
    vector<int> p, r;
    DSU(int n=0){ init(n); }
    void init(int n){ p.resize(n); r.assign(n,0); iota(p.begin(), p.end(), 0); }
    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }
    bool unite(int a,int b){
        a = find(a); b = find(b);
        if(a==b) return false;
        if(r[a]<r[b]) swap(a,b);
        p[b]=a;
        if(r[a]==r[b]) r[a]++;
        return true;
    }
};

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n,k,m;
    if(!(cin>>n>>k>>m)) return 0;
    vector<int> terminals(k);
    for(int i=0;i<k;i++){
        cin>>terminals[i];
        terminals[i]--; // zero-based
    }
    vector<Edge> edges;
    edges.reserve(m);
    for(int i=0;i<m;i++){
        int u,v; ll w;
        cin>>u>>v>>w;
        u--; v--;
        edges.push_back({u,v,w});
    }

    // nếu n quá lớn, phương pháp này sẽ chậm; ta cảnh báo nhưng vẫn chạy.
    if(n > 23){
        // với n>23, 2^n quá lớn để liệt kê tập đỉnh; bạn nên dùng DP-Steiner.
        // Nhưng vẫn cố chạy nếu người dùng muốn (có thể rất chậm).
    }

    // bitmask terminals requirement
    int needMask = 0;
    for(int t: terminals) needMask |= (1<<t);

    // Nhưng needMask above incorrectly uses full n-bit indexing.
    // Vì n có thể > 31 (bit shift overflow). To avoid this, we should map vertices
    // to bits only when n <= 30. We assume n <= 20 per subtask. If n > 30, stop.
    if(n > 30){
        cerr << "n too large for subset-enumeration approach (n should be <=~30)\n";
        return 0;
    }

    // Build bitmask of terminals for n bits (safe since we guard n<=30)
    int termMask = 0;
    for(int t: terminals) termMask |= (1<<t);

    ll ans = INF;
    int FULL = 1<<n;
    // Enumerate all vertex subsets mask: mask indicates which vertices are included
    for(int mask = 0; mask < FULL; ++mask){
        // must include all terminals
        if( (mask & termMask) != termMask ) continue;

        int cntV = __builtin_popcount(mask);
        if(cntV <= 1) continue; // can't connect >=2 terminals unless cntV>1

        // collect edges internal to mask
        vector<pair<ll, pair<int,int>>> E;
        E.reserve(m);
        for(auto &e: edges){
            if( (mask & (1<<e.u)) && (mask & (1<<e.v)) ){
                E.push_back({e.w, {e.u, e.v}});
            }
        }
        if((int)E.size() < cntV-1) continue; // not enough edges to connect

        sort(E.begin(), E.end(), [](auto &a, auto &b){ return a.first < b.first; });

        DSU dsu(n);
        ll total = 0;
        int used = 0;
        for(auto &ee: E){
            int u = ee.second.first;
            int v = ee.second.second;
            ll w = ee.first;
            if(dsu.unite(u,v)){
                total += w;
                used++;
                if(used == cntV - 1) break;
            }
        }
        if(used == cntV - 1){
            ans = min(ans, total);
        }
    }

    if(ans == INF) {
        // theo đề sẽ luôn có đường đi giữa mọi đôi đỉnh, nên ko hy vọng vô nghiệm
        cout << "-1\n";
    } else {
        cout << ans << "\n";
    }

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...