0w1

UVA 1151 Buy or Build ( 枚舉 + 最小生成樹 )

UVa Online Judge
先計算完全沒有用子網路集的生成樹,留下可能用到的 n - 1 條邊,再二進位枚舉子網路的可能子集。這麼做可以大大減少考慮不可能用到的邊。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 3;
const int MAXM = MAXN * MAXN / 2;
const int MAXQ = 8 + 2;

struct Edge{
    int u, v, w;
    Edge(){}
    Edge(int _u, int _v, int _w): u(_u), v(_v), w(_w){}
    bool operator < (const Edge &oth) const{
        return w < oth.w;
    }
} es[MAXM];

struct UnionFind{
    int fa[MAXN];
    void init(int n){
        for(int i = 0; i <= n; ++i)
            fa[ i ] = i;
    }
    int find(int x){ return x == fa[ x ] ? x : fa[x] = find( fa[x] ); }
    bool unite(int a, int b){
        int x = find( a ), y = find( b );
        if( x == y ) return false;
        fa[ x ] = y; return true;
    }
} uf;

int n, m, q;
int subnet_size[MAXQ], subnet_cost[MAXQ], subnet[MAXQ][MAXN];
int x[MAXN], y[MAXN];

struct Kruskal{
    vector<Edge> chose_edge;
    int solveWithoutSubnet(){
        chose_edge.clear();
        uf.init( n );
        sort( es, es + m );
        int cost = 0;
        for(int i = 0; i < m; ++i){
            int u = es[i].u, v = es[i].v, w = es[i].w;
            if( uf.unite( u, v ) ){
                cost += w;
                chose_edge.push_back( es[ i ] );
                if( chose_edge.size() == n - 1 ) break;
            }
        }
        assert( chose_edge.size() == n - 1 );
        return cost;
    }
    int solveWithSubnets(int S){
        uf.init( n );
        int cost = 0, picked = 0;
        for(int i = 0; i < q; ++i)
            if( S & ( 1 << i ) ){
                cost += subnet_cost[ i ];
                for(int j = 0; j < subnet_size[ i ]; ++j)
                    for(int k = j + 1; k < subnet_size[ i ]; ++k)
                        if( uf.unite( subnet[ i ][ j ], subnet[ i ][ k ] ) )
                            ++picked;
            }
        if( picked == n - 1 ) return cost;
        for(Edge &e: chose_edge){
            int u = e.u, v = e.v, w = e.w;
            if( uf.unite( u, v ) ){
                cost += w;
                if( ++picked == n - 1 ) break;
            }
        }
        assert( picked == n - 1 );
        return cost;
    }
} mst;

int euDis2(int a, int b){
    int dx2 = ( x[ a ] - x[ b ] ) * ( x[ a ] - x[ b ] );
    int dy2 = ( y[ a ] - y[ b ] ) * ( y[ a ] - y[ b ] );
    return dx2 + dy2;
}

void getEdgeCost(){
    m = 0;
    for(int i = 1; i < n; ++i)
        for(int j = i + 1; j <= n; ++j)
            es[ m++ ] = Edge( i, j, euDis2( i, j ) );
}

void solve(){
    getEdgeCost();
    int ans = mst.solveWithoutSubnet();
    for(int i = 1; i < ( 1 << q ); ++i)
        ans = min( ans, mst.solveWithSubnets( i ) );
    printf("%d\n", ans);
}

int main(){
    int T; scanf("%d" ,&T);
    while( T-- ){
        scanf("%d%d",&n, &q);
        for(int i = 0; i < q; ++i){
            scanf("%d%d", &subnet_size[i], &subnet_cost[i]);
            for(int j = 0; j < subnet_size[i]; ++j)
                scanf("%d", &subnet[i][j]);
        }
        for(int i = 1; i <= n; ++i) // citits are 1 idx
            scanf("%d%d", &x[i], &y[i]);
        solve();
        if( T ) puts("");
    }
    return 0;
}