uva 1151 Buy or Build (最小生成树)

来源:互联网 发布:html点击按钮执行js 编辑:程序博客网 时间:2024/05/19 15:42

uva 1151 Buy or Build

题目大意:给出n个点以及m种套餐,每种套餐的数据包括改套餐所包含点的数量,该套餐的费用,以及改套餐所包含的具体的点的编号。点与点之间的费用是他们的欧几里得距离的平方。现在问,在使用套餐的情况下连接所有点的最小费用。套餐可以叠加。

解题思路:先求出不用套餐构造最小生成树的最小费用。然后开始枚举用或不用改套餐构造最小生成树的费用(二进制枚举子集),维护该费用,最小值就是答案。

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <cstdlib>using namespace std;typedef long long ll;const int N = 1005;const int M = N * N;int n, p;int X[N], Y[N];int fa[N];struct SubNet{    int num, cost;    int rec[N];}sn[10];struct Edge{    int u, v;       ll len;}edges[M];int en;int cmp(Edge a, Edge b) {    return a.len < b.len;} ll getlen(int x, int y) {    return pow(X[x] - X[y], 2) + pow(Y[x] - Y[y], 2);}int find(int x) {    return x == fa[x] ? x : fa[x] = find(fa[x]); }void init() {    en = 0;    for (int i = 0; i < N ;i++) fa[i] = i;}   void input() {    for (int i = 0; i < p; i++) {        scanf("%d %d", &sn[i].num, &sn[i].cost);            for (int j = 0; j < sn[i].num; j++) {            scanf("%d", &sn[i].rec[j]);         }    }       for (int i = 1; i <= n; i++) {        scanf("%d %d", &X[i], &Y[i]);       }    for (int i = 1; i <= n; i++) {        for (int j = i + 1; j <= n; j++) {            edges[en++] = (Edge){i, j, getlen(i, j)};           }    }    sort(edges, edges + en, cmp);}ll kruskal() {    ll ans = 0;    for (int i = 0; i < en; i++) {        int x = find(edges[i].u), y = find(edges[i].v);        if (x != y) {            fa[x] = y;            ans += edges[i].len;        }    }    return ans;}void solve() {    ll ans = kruskal();    for (int B = 0; B < (1 << p); B++) {        ll temp = 0;        for (int i = 0; i <= n; i++) fa[i] = i;        for (int i = 0; i < p; i++) {            if (B & (1 << i)) {                temp += sn[i].cost;                for (int j = 1; j < sn[i].num; j++) {                    fa[find(sn[i].rec[j - 1])] = find(sn[i].rec[j]);                    }            }        }        temp += kruskal();        ans = min(ans, temp);    }    printf("%lld\n", ans);}int main() {    int T;    scanf("%d", &T);    while (T--) {        scanf("%d %d", &n, &p);             init();        input();        solve();        if (T) puts("");    }    return 0;}
0 0