首页 > 代码库 > UVa 1151 买还是建

UVa 1151 买还是建

 https://vjudge.net/problem/UVA-1151

题意:

平面上有n个点,你的任务是让所有n个点连通。为此,你可以新建一些边,费用等于两个端点的距离平方和。另外还有q个套餐可以购买,如果你购买了第i个套餐,该套餐中的所有结点都变得相互连通,第i个套餐的花费为Ci。

 

思路:

这道题比较容易超时。可能需要用到并查集的路径压缩,我下面的代码就是用了路径压缩,不然要超时。也是看了别人的代码才知道还有这种省时间的做法。

先介绍一下路径压缩吧:

技术分享

如果并查集像一字长蛇这样排列的话,寻找起来就比较费时间,但如果像图2一样的话,一下子就可以找到根了。压缩的方法也是挺简单的。

1     int r = x;2     while (r != p[r])  r = p[r];3     int i = x, j;4     while (p[i] != r) 5     {6         j = p[i];7         p[i] = r;8         i = j;9     }

题目的做法就像紫书上说的那样,先不考虑套餐算一遍,然后枚举套餐的方法,这里的话二进制枚举法非常方便。

  1 #include<iostream>   2 #include<cstring>  3 #include<algorithm>  4 #include<vector>  5 using namespace std;  6   7 const int maxn = 1000 + 5;  8   9 int n, m, q, cnt; 10 int p[maxn]; 11 vector<int> g[10];  //方案集合 12 int c[10];          //方案价格 13  14 // 15 struct node 16 { 17     int u; 18     int v; 19     int dist; 20 }edge[maxn*maxn]; 21  22 // 23 struct node2 24 { 25     int x, y; 26 }a[maxn]; 27  28 int find(int x) 29 { 30     //return p[x] == x ? x : find(p[x]);   用这个会超时 31     //路径压缩 32     int r = x; 33     while (r != p[r])  r = p[r]; 34     int i = x, j; 35     while (p[i] != r)  36     { 37         j = p[i]; 38         p[i] = r; 39         i = j; 40     } 41     return r; 42 } 43  44 bool cmp(node a, node b) 45 { 46     return a.dist < b.dist; 47 } 48  49 //计算距离平方和 50 int cacl_dist(node2 a, node2 b) 51 { 52     return (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y); 53 } 54  55 void init() 56 { 57     for (int k = 1; k <= n; k++)   p[k] = k; 58 } 59  60 int Kruskal() 61 { 62     int num = 0; 63     int ans = 0; 64     for (int i = 0; i < cnt ; i++) 65     { 66         int x = find(edge[i].u); 67         int y = find(edge[i].v); 68         if (x != y) 69         { 70             p[x] = y; 71             ans += edge[i].dist; 72             num++; 73         } 74         if (num == n - 1)  return ans; 75     } 76     return ans; 77 } 78  79  80 void solve() 81 { 82     init(); 83     int ans = Kruskal(); 84     //二进制枚举方案 85     for (int i = 0; i < (1 << q); i++) 86     { 87         init(); 88         int cost = 0; 89         for (int j = 0; j < q; j++) 90         { 91             if (i & (1 << j)) 92             { 93                 cost += c[j]; 94                 int x = find(g[j][0]); 95                 for (int k = 1; k < g[j].size(); k++) 96                 {     97                     int y = find(g[j][k]); 98                     if (x != y) 99                         p[y] = x;100                 }101             }102         }103         ans = min(cost + Kruskal(), ans);104     }105     printf("%d\n", ans);106 }107 108 int main()109 {110     //freopen("D:\\txt.txt", "r", stdin);111     int T, t, s, kase=0;112     scanf("%d", &T);113     while (T--)114     {115         if (++kase > 1)    printf("\n");116         scanf("%d%d", &n, &q);117 118         //存储方案119         for (int i = 0; i < q; i++)120         {121             g[i].clear();122             scanf("%d", &t);123             scanf("%d", &c[i]);124             for (int j = 0; j < t; j++)125             {126                 scanf("%d", &s);127                 g[i].push_back(s);    128             }129         }130 131         for (int i = 1; i <= n; i++)132             scanf("%d%d", &a[i].x, &a[i].y);133 134         //存储边135         cnt = 0;136         for (int i = 1; i <= n;i++)137         for (int j = i + 1; j <= n; j++)138         {139             edge[cnt].u = i;140             edge[cnt].v = j;141             edge[cnt].dist = cacl_dist(a[i], a[j]);142             cnt++;143         }144         sort(edge, edge + cnt, cmp);145         solve();146     }147     return 0;148 }

 

UVa 1151 买还是建