[NOIp 2017]宝藏
2017-12-17 14:02
417 查看
Description
参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度。小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远, 也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多。
小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。
在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以 任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏 屋之间的道路无需再开发。
新开发一条道路的代价是:
$$\mathrm{L} \times \mathrm{K}$$
L代表这条道路的长度,K代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。
请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代 价最小,并输出这个最小值。
Input
第一行两个用空格分离的正整数 n 和 m,代表宝藏屋的个数和道路数。接下来 m 行,每行三个用空格分离的正整数,分别是由一条道路连接的两个宝藏 屋的编号(编号为 1~n),和这条道路的长度 v。
Output
输出共一行,一个正整数,表示最小的总代价。Sample Input1
4 51 2 1
1 3 3
1 4 1
2 3 4
3 4 1
Sample Output1
4Sample Explanation1
![](https://oscdn.geek-share.com/Uploads/Images/Content/202011/20/6c2df57057c36ace7f8783baadfd582a.png)
Sample Input2
4 51 2 1
1 3 3
1 4 1
2 3 4
3 4 2
Sample Output2
5Sample Explanation2
![](https://oscdn.geek-share.com/Uploads/Images/Content/202011/20/270303eecba069839d8d4c85688532c9.png)
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)$。
//Is is made by Awson on 2017.12.17 #include <set> #include <map> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define Max(a, b) ((a) > (b) ? (a) : (b)) #define Min(a, b) ((a) < (b) ? (a) : (b)) using namespace std; const int N = 12; const int SIZE = 1<<12; const int INF = ~0u>>1; int n, m, u, v, c, U; int g[N+5][N+5]; LL sval[N+5][SIZE+5], qval[SIZE+5][SIZE+5], f[N+5][SIZE+5]; void work() { scanf("%d%d", &n, &m); U = (1<<n)-1; memset(g, 127, sizeof(g)); for (int i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &c); g[u][v] = g[v][u] = Min(c, g[u][v]); } memset(sval, 127/3, sizeof(sval)); for (int u = 1; u <= n; u++) for (int i = 0; i <= U; i++) for (int v = 1; v <= n; v++) if ((1<<v-1)&i) sval[u][i] = Min(sval[u][i], 1ll*g[u][v]); memset(qval, 127/3, sizeof(qval)); for (int i = 0; i <= U; i++) { int C = i^U; for (int j = C; j; j = (j-1)&C) { LL cnt = 0; for (int u = 1; u <= n; u++) if ((1<<u-1)&j) cnt += sval[u][i]; qval[j][i] = Min(qval[j][i], cnt); } } LL ans = 1ll*INF; for (int root = 1; root <= n; root++) { memset(f, 127/3, sizeof(f)); LL inf = f[0][0]; f[0][1<<root-1] = 0; for (int dep = 0; dep < n; dep++) for (int i = 0; i <= U; i++) if (f[dep][i] != inf) { int C = i^U; for (int j = C; j; j = (j-1)&C) f[dep+1][i|j] = Min(f[dep+1][i|j], f[dep][i]+qval[j][i]*(dep+1)); } for (int i = 0; i < n; i++) ans = Min(ans, f[i][U]); } printf("%lld\n", ans); } int main() { work(); return 0; }
相关文章推荐
- 【NOIP 2017】宝藏
- NOIP2017 宝藏
- NOIP2017 提高Day2-2 宝藏 解题报告
- [NOIp2017] 宝藏
- NOIP2017 Day2 T2 宝藏(状压DP)
- NOIP2017 宝藏 题解报告【状压dp】
- NOIP2017 宝藏 题解报告【状压dp】
- luogu3959【noip2017】宝藏(状压dp)
- NOIP 2017 宝藏 (状压,搜索)
- 5477. 【NOIP2017提高组正式赛】宝藏
- [NOIP2017] 宝藏 【树形DP】【状压DP】
- [NOIP2017][luogu3959]宝藏treasure
- JZOJ 5477. 【NOIP2017提高组正式赛】宝藏
- #333. 【NOIP2017】宝藏
- [NOIP2017]宝藏 状压DP
- NOIP2017提高组D2T2[宝藏]
- [NOIP2017] 宝藏
- [NOIp2017 Day2 T2] 宝藏treasure (状压dp)
- 【NOIP2017】宝藏(状压DP)
- [Noip2017] 宝藏