UVa 1151 - Buy or Build(最小生成树)

Posted hkxy125

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa 1151 - Buy or Build(最小生成树)相关的知识,希望对你有一定的参考价值。

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3592

 

题意:

平面上有n个点(1≤n≤1000),你的任务是让所有n个点连通。
为此,你可以新建一些边,费用等于两个端点的欧几里德距离的平方。
另外还有q(0≤q≤8)个“套餐”可以购买,如果你购买了第i个套餐,该套餐中的所有结点将变得相互连通。
第i个套餐的花费为Ci。求最小的花费。

 

分析:

最容易想到的算法是:先枚举购买哪些套餐,把套餐中包含的边的权值设为0,然后求最小生成树。
由于枚举量为O(2^q),给边排序的时间复杂度为O(n*nlogn),而排序之后每次Kruskal算法的时间复杂度为O(n*n),
因此总时间复杂度为O((2^q)*(n*n)+n*nlogn),对于题目的规模来说太大了。
只需一个小小的优化即可降低时间复杂度:先求一次原图(不购买任何套餐)的最小生成树,
得到n-1条边,然后每次枚举完套餐后只考虑套餐中的边和这n-1条边,
则枚举套餐之后再求最小生成树时,图上的边已经寥寥无几。
为什么可以这样呢?首先回顾一下,在Kruskal算法中,哪些边不会进入最小生成树。
答案是:两端已经属于同一个连通分量的边。买了套餐以后,相当于一些边的权变为0,
而对于不在套餐中的每条边e,排序在e之前的边一个都没少,反而可能多了一些权值为0的边,
所以在原图Kruskal时被“扔掉”的边,在后面的Kruskal中也一样会被扔掉。

 

代码:

 1 import java.io.*;
 2 import java.util.*;
 3 import static java.lang.Math.*;
 4 
 5 public class Main {
 6     Scanner cin = new Scanner(new BufferedInputStream(System.in));
 7     final int UP = 1000 + 5;
 8     int pre[] = new int[UP];
 9     int x[] = new int[UP], y[] = new int[UP], cost[] = new int[UP];
10     
11     class Edge implements Comparable<Edge> {
12         int f, b, v;
13         
14         @Override
15         public int compareTo(Edge that) {
16             return v - that.v;
17         }
18     }
19     
20     int seek(int v) {
21         return pre[v] == v ? v : (pre[v] = seek(pre[v]));
22     }
23     
24     int MST(int n, ArrayList<Edge> e, ArrayList<Edge> res) {
25         if(n <= 1) return 0;
26         int m = e.size(), ans = 0;
27         for(int i = 0; i < m; i++) {
28             int pf = seek(e.get(i).f), pb = seek(e.get(i).b);
29             if(pf == pb) continue;
30             pre[pf] = pre[pb];
31             ans += e.get(i).v;
32             if(res != null) res.add(e.get(i));
33             if(--n == 1) break;
34         }
35         return ans;
36     }
37     
38     void MAIN() {
39         int T;
40         T = cin.nextInt();
41         while(T --> 0) {
42             @SuppressWarnings("unchecked")
43             ArrayList<Integer> subn[] = new ArrayList[8];
44             for(int i = 0; i < 8; i++) subn[i] = new ArrayList<Integer>();
45             int n = cin.nextInt();
46             int q = cin.nextInt();
47             for(int m, i = 0; i < q; i++) {
48                 m = cin.nextInt();
49                 cost[i] = cin.nextInt();
50                 for(int t = 0; t < m; t++) subn[i].add(cin.nextInt()-1);
51             }
52             for(int i = 0; i < n; i++) {
53                 x[i] = cin.nextInt();
54                 y[i] = cin.nextInt();
55             }
56             
57             ArrayList<Edge> edge = new ArrayList<Edge>();
58             for(int i = 0; i < n; i++) {
59                 for(int t = i+1; t < n; t++) {
60                     Edge e = new Edge();
61                     e.f = i;  e.b = t;
62                     e.v = (x[i]-x[t])*(x[i]-x[t]) + (y[i]-y[t])*(y[i]-y[t]);
63                     edge.add(e);
64                 }
65             }
66             
67             ArrayList<Edge> used = new ArrayList<Edge>();
68             for(int i = 0; i < n; i++) pre[i] = i;
69             Collections.sort(edge);
70             int ans = MST(n, edge, used);
71             for(int s = 1; s < (1<<q); s++) {
72                 for(int i = 0; i < n; i++) pre[i] = i; // 初始化并查集
73                 int remain = n, c = 0;
74                 for(int i = 0; i < q; i++) if((s&(1<<i)) > 0) {
75                     c += cost[i];
76                     for(int t = 1; t < subn[i].size(); t++) {
77                         int pf = seek(subn[i].get(0)), pb = seek(subn[i].get(t));
78                         if(pf == pb) continue;
79                         pre[pf] = pb;
80                         remain--;
81                     }
82                 }
83                 ans = min(ans, c + MST(remain, used, null));
84             }
85             System.out.println(ans);
86             if(T > 0) System.out.println();
87         }
88     }
89     
90     public static void main(String args[]) { new Main().MAIN(); }
91 }

 













以上是关于UVa 1151 - Buy or Build(最小生成树)的主要内容,如果未能解决你的问题,请参考以下文章

[UVA - 1151] Buy or Build 题解

UVa 1151 - Buy or Build(最小生成树)

UVa1151 Buy or Build (最小生成树,枚举子集)

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

UVa 1151 Buy or Build (最小生成树+二进制法暴力求解)

UVA 1151 Buy or Build (有某些特别的东东的最小生成树)