zoukankan      html  css  js  c++  java
  • [NOIp 2017]宝藏

    Description

    参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度。

    小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远, 也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多。

    小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。

    在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以 任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏 屋之间的道路无需再开发。

    新开发一条道路的代价是:

    $$mathrm{L} imes mathrm{K}$$

    L代表这条道路的长度,K代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。

    请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代 价最小,并输出这个最小值。

    Input

    第一行两个用空格分离的正整数 n 和 m,代表宝藏屋的个数和道路数。

    接下来 m 行,每行三个用空格分离的正整数,分别是由一条道路连接的两个宝藏 屋的编号(编号为 1~n),和这条道路的长度 v。

    Output

    输出共一行,一个正整数,表示最小的总代价。

    Sample Input1

    4 5
    1 2 1
    1 3 3
    1 4 1
    2 3 4
    3 4 1

    Sample Output1

    4

    Sample Explanation1

    Sample Input2

    4 5
    1 2 1
    1 3 3
    1 4 1
    2 3 4
    3 4 2

    Sample Output2

    5

    Sample Explanation2

    HINT

    对于 20%的数据: 保证输入是一棵树,$1 le n le 8$,$v le 5000$ 且所有的 v 都相等。

    对于 40%的数据: $1 le n le 8$,$0 le m le 1000$,$v le 5000$ 且所有的 v 都相等。

    对于 70%的数据: $1 le n le 8$,$0 le m le 1000$,$v le 5000$

    对于 100%的数据: $1 le n le 12$,$0 le m le 1000$,$v le 500000$

    题解

    很容易想到最后构成的图就是一棵树。

    比较容易想到的$70pts$就是用搜索来确定这棵树的形态。

    我们先枚举根节点,再搜索来确定其父节点。

    正解则是子集$DP$了。

    我们考虑到什么状态是无后效性的?记$f_{dep,i}$,表示生成树中最深的点深度为$dep$,选点的状态为$i$的最小花费。

    转移的话就是考虑第$dep+1$层需要连接哪些点,即$$f_{dep+1,i|j} = min {f_{dep,i}+(dep+1)*qval_{j,i}}$$

    其中$j$表示第$dep+1$层连的点,$i∩j =  emptyset$;$qval_{j,i}$表示集合$j$中所有的点连向集合$i$中的点最小花费和。

    对于$qval$的值我们可以通过$$qval_{j,i} = sum_{u∈j} sval_{u,i}$$

    计算出,其中$sval_{u,i}$表示点$u$到集合$i$中的点最小距离。

    显然$$sval_{u,i} = min_{v∈i} {w[u][v]}$$

    值得注意的是,其中会有很多不合法的状况,比如对于转移时$j$集合中的点并不是严格的在第$dep+1$层。但可以证明的是,这种不合法的情况总比最优解差。我们允许这种不合法的情况存在。

    时间复杂度$O(3^n*n^2)$。

     1 //Is is made by Awson on 2017.12.17
     2 #include <set>
     3 #include <map>
     4 #include <cmath>
     5 #include <ctime>
     6 #include <queue>
     7 #include <stack>
     8 #include <cstdio>
     9 #include <string>
    10 #include <vector>
    11 #include <cstdlib>
    12 #include <cstring>
    13 #include <iostream>
    14 #include <algorithm>
    15 #define LL long long
    16 #define Max(a, b) ((a) > (b) ? (a) : (b))
    17 #define Min(a, b) ((a) < (b) ? (a) : (b))
    18 using namespace std;
    19 const int N = 12;
    20 const int SIZE = 1<<12;
    21 const int INF = ~0u>>1;
    22 
    23 int n, m, u, v, c, U;
    24 int g[N+5][N+5];
    25 LL sval[N+5][SIZE+5], qval[SIZE+5][SIZE+5], f[N+5][SIZE+5];
    26 
    27 void work() {
    28     scanf("%d%d", &n, &m); U = (1<<n)-1;
    29     memset(g, 127, sizeof(g));
    30     for (int i = 1; i <= m; i++) {
    31         scanf("%d%d%d", &u, &v, &c);
    32         g[u][v] = g[v][u] = Min(c, g[u][v]);
    33     }
    34     memset(sval, 127/3, sizeof(sval));
    35     for (int u = 1; u <= n; u++)
    36         for (int i = 0; i <= U; i++)
    37             for (int v = 1; v <= n; v++)
    38                 if ((1<<v-1)&i) sval[u][i] = Min(sval[u][i], 1ll*g[u][v]);
    39     memset(qval, 127/3, sizeof(qval));
    40     for (int i = 0; i <= U; i++) {
    41         int C = i^U;
    42         for (int j = C; j; j = (j-1)&C) {
    43             LL cnt = 0;
    44             for (int u = 1; u <= n; u++)
    45                 if ((1<<u-1)&j) cnt += sval[u][i];
    46             qval[j][i] = Min(qval[j][i], cnt);
    47         }
    48     }
    49     LL ans = 1ll*INF;
    50     for (int root = 1; root <= n; root++) {
    51         memset(f, 127/3, sizeof(f)); LL inf = f[0][0];
    52         f[0][1<<root-1] = 0;
    53         for (int dep = 0; dep < n; dep++)
    54             for (int i = 0; i <= U; i++) if (f[dep][i] != inf) {
    55                 int C = i^U;
    56                 for (int j = C; j; j = (j-1)&C)
    57                     f[dep+1][i|j] = Min(f[dep+1][i|j], f[dep][i]+qval[j][i]*(dep+1));
    58             }
    59         for (int i = 0; i < n; i++) ans = Min(ans, f[i][U]);
    60     }
    61     printf("%lld
    ", ans);
    62 }
    63 int main() {
    64     work();
    65     return 0;
    66 }
  • 相关阅读:
    20192329 2020-2021-1 《数据结构与面向对象程序设计》课程总结
    20192329 2020-2021-1《数据结构与面向对象程序设计》实验九报告
    20192329李元和《数据结构与面向对象程序设计》实验八报告
    20192329 2020-2021-1《数据结构与面向对象程序设计》实验七报告
    学号 20192329 李元和《数据结构与面向对象程序设计》实验六报告
    20192329 李元和 2020-2021-1《数据结构与面向对象程序设计》实验五报告
    学号20192329 2020-2021-1《数据结构与面向对象程序设计》实验四报告
    学号 20192329 李元和《数据结构与面向对象程序设计》实验三报告
    学号 20192329 李元和《数据结构与面向对象程序设计》实验二报告
    学号 20192329 李元和《数据结构与面向对象程序设计》实验一报告
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8051892.html
Copyright © 2011-2022 走看看