• UVa 1151


    链接:

    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 }
  • 相关阅读:
    江の島西浦写真館2-1
    江の島西浦写真館1-2
    Oracle 查询表空间使用情况
    Oracle 的开窗函数 rank,dense_rank,row_number
    oracle11G 用户密码180天修改概要文件过程
    CentOS6 安装 MySQL5.7
    linux下SS 网络命令详解
    CentOS6 网络设置
    redhat 6 红帽6 Linux 网络配置
    Oracle分析函数——函数列表
  • 原文地址:https://www.cnblogs.com/hkxy125/p/9527568.html
Copyright © 2020-2023  润新知