UVA1151 最小生成树

2017年7月19日

题目的大意是平面上有 n 个点,让你将这 n 个点连接起来,连接任意两个点间的费用为两点间欧几里得距离的平方.同时有 q 个套餐,买第 qi 个套餐花费 ci .买了某个套餐后,套餐中所有点都已经连接.求将所有点连起来的最小花费.

做法是用二进制的思想来枚举购买哪些套餐,将套餐中的点加入到并查集中.然后求最小生成树就好了.

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, q;
struct point {
    int x, y;
} p[N];
struct edge {
    int from, to, cost;
    bool operator < (const edge & a) const {
        return cost < a.cost;
    }
} e[N * N];
int f[N * N];
int root(int x)
{
    return x == f[x] ? x : f[x] = root(f[x]);
}
vector<int> vip[10];
int vipcost[10];
int main()
{
    int tt;
    scanf("%d", &tt);
    bool flag = false;
    while (tt--) {
        if (flag)
            putchar('\n');
        if (!flag)
            flag = true;
        scanf("%d %d", &n, &q);
        for (int i = 0; i < q; i++) {
            vip[i].clear();
            int a;
            scanf("%d %d", &a, &vipcost[i]);
            while (a--) {
                int x;
                scanf("%d", &x);
                vip[i].push_back(x);
            }
        }
        for (int i = 0; i < n; i++) {
            scanf("%d %d", &p[i].x, &p[i].y);
        }
        int cnt = 0;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                int cost = (p[i].x - p[j].x) * (p[i].x - p[j].x) + (p[i].y - p[j].y) * (p[i].y - p[j].y);
                e[cnt].from = i + 1;
                e[cnt].to = j + 1;
                e[cnt].cost = cost;
                cnt++;
            }
        }
        sort(e, e + cnt);
        int ans = (int) 1e9;
        for (int s = 0; s < 1 << q; s++) {
            int cost = 0;
            for (int i = 1; i <= cnt; i++) {
                f[i] = i;
            }
            for (int i = 0; i < q; i++) {
                if (s & 1 << i) {
                    cost += vipcost[i];
                    for (int k = 0; k < (int) vip[i].size() - 1; k++) {
                        f[root(vip[i][k])] = root(vip[i][k + 1]);
                    }
                }
            }
            for (int i = 0; i < cnt; i++) {
                if (root(e[i].from) == root(e[i].to))
                    continue;
                f[root(e[i].from)] = root(e[i].to);
                cost += e[i].cost;
            }
            ans = min(ans, cost);
        }
        cout << ans << endl;
    }
    return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注