bzoj 2753 [SCOI 2012] 滑雪与时间胶囊 - Prim

题目传送门

  传送点I

  传送点II

题目大意

  给定一个有$n$个点$m$条边的图,每个点有一个高度$h_{i}$,能从$u$经过一条边到达$v$,当且仅当存在一条边是$(u, v)$或$(v, u)$,且$h_{u}\geqslant h_{v}$。问1号点能到达的所有点的最小树形图的边权和。

  第一问沙雕问题。直接一个搜索水过。

  第二问,好像是最小树形图。看着数据范围,嗯,别想朱-刘了。

  感觉可以直接Prim。于是愉快地WA了一发。来回顾一下Prim算法的正确性证明

可以不妨设图中所有边的权重都不同,这样最小生成树是唯一的

设Prim算法得到$G$,而最小生成树是$T$。考虑用反证法。

设在生成G的过程中第一次产生的不在T中的边是$e$,未加入$e$时的点集为$V$。

把$e$加入$T$之后会出现环,这个环内必然存在一条边$f = (u, v) \neq e$使得$u\in V, v\notin V$(因为$e$的一个端点不在$V$中)。由Prim的贪心策略可知$w(e) < w(f)$。用$e$替换掉$f$可以得到更优的生成树,这与最小生成树矛盾。因此$T = G$。

  但树形图不像树那么简单。如果尝试用这种方法去证明可以发现需要讨论两条边的方向,于是很轻松就能卡掉这个zz做法。

  然后如何hack这个zz做法呢?

  于是这个假做法跑出了497的优秀答案。

  好了好了,开始说正题。

  因为不能用朱-刘算法,考虑这样的图有什么样的性质。

  把通过双向边连通的点缩起来。这样剩一个DAG。

  考虑对于一个被缩起来的一块,它自己相当于一个无向图,可以用最小生成树的算法。

  对于连向这个块的出边,它们选还是不选入树形图只对这个块中的选边有影响。

  因此可以将前面的块都看成一个点。然后很有趣的事情来了,直接把这些有向边看成无向边,然后上MST算法。

  为什么这样做是对的。因为我们可以将任意一个树形图映射成一个边权和与它相等的生成树或者一个生成树映射成一个边权和与它相等的树形图。

  做法很简单。前一部分直接将有向边看成无向边,后一部分从 "前面的块都看成一个点" 指的点开始沿着树边bfs,这样就可以定向了。

  具体实现不用将前面的块缩起来。直接以结束点的高度为第一关键字,边权为第二关键字排序即可。

  (虽然我很好奇为什么大家都写Kruskal。显然写Prim可以少写点东西)

Code

 1 /**
 2  * bzoj
 3  * Problem#
 4  * Accepted
 5  * Time: 13128ms
 6  * Memory: 53364k
 7  */
 8 #include <bits/stdc++.h>
 9 #ifndef WIN32
10 #define Auto "%lld"
11 #else
12 #define Auto "%I64d"
13 #endif
14 using namespace std;
15 typedef bool boolean;
16
17 typedef class Edge {
18     public:
19         int ed, w;
20
21         Edge() {    }
22         Edge(int ed, int w):ed(ed), w(w) {    }
23 }Edge;
24
25 int n, m;
26 int *hs;
27 boolean* added;
28 vector<Edge> *g;
29
30 boolean operator < (const Edge& a, const Edge& b) {
31     if (hs[a.ed] ^ hs[b.ed])    return hs[a.ed] < hs[b.ed];
32     return a.w > b.w;
33 }
34
35 inline void init() {
36     scanf("%d%d", &n, &m);
37     hs = new int[(n + 1)];
38     added = new boolean[(n + 1)];
39     g = new vector<Edge>[(n + 1)];
40     memset(added, false, sizeof(boolean) * (n + 1));
41     for (int i = 1; i <= n; i++)
42         scanf("%d", hs + i);
43     for (int i = 1, u, v, w; i <= m; i++) {
44         scanf("%d%d%d", &u, &v, &w);
45         if (hs[u] >= hs[v])
46             g[u].push_back(Edge(v, w));
47         if (hs[u] <= hs[v])
48             g[v].push_back(Edge(u, w));
49     }
50 }
51
52 int rc = 1;
53 long long rv = 0;
54 priority_queue<Edge> que;
55 inline void solve() {
56     added[1] = true;
57     for (int i = 0; i < (signed) g[1].size(); i++)
58         que.push(g[1][i]);
59     while (!que.empty()) {
60         while (!que.empty() && added[que.top().ed])
61             que.pop();
62         if (que.empty())
63             break;
64         Edge e = que.top();
65         que.pop();
66         added[e.ed] = true, rc++, rv += e.w;
67         for (int i = 0; i < (signed) g[e.ed].size(); i++)
68             que.push(g[e.ed][i]);
69     }
70     printf("%d "Auto, rc, rv);
71 }
72
73 int main() {
74     init();
75     solve();
76     return 0;
77 }

原文地址:https://www.cnblogs.com/yyf0309/p/9426473.html

时间: 2024-11-10 13:20:29

bzoj 2753 [SCOI 2012] 滑雪与时间胶囊 - Prim的相关文章

BZOJ 2753 SCOI 2012 滑雪与时间胶囊 最小生成树

题目大意:在滑雪场中,每一个景点有一个高度.现在小明在一号节点.i和j之间有单向边当且仅当i的高度不高于j.问小明最多可以去多少个景点,和最小总费用. 思路:这是一道数学证明的好题. 第一问比较水,直接将可行的边连接起来,然后BFS出解. 第二问就比较难搞了.不难看出,直接用朱刘算法是不可行的,因为朱刘算法的时间复杂度达到了O(mn),而这个题至少需要一个O(mlogm)的算法. 恩?你说mlogm?难道是最小生成树?但是这图中都是单向边啊. 经过了上网找题解,和同学研究之后,终于弄明白了这题的

BZOJ 2754 SCOI 2012 喵星球上的点名 后缀数组

题目大意:在喵星球上有一些喵~,每个喵都有一个姓和一个名字.点名的时候如果一个喵中姓或者名中有这个串的话他就会喵.问每次点名有几个喵喵了,和每个喵喵了几次. 思路:好萌的题喵~ AC自动机构造fail树是可以做的,但是和SA乱搞的时间差不多,我就是SA乱搞的w 把所有的串(姓名,询问)用$连接成一个串,然后做后缀数组,height数组.过程中记录一下每一个后缀数属于哪个喵,还有询问在串中的起始位置.在处理询问的时候,可以同过sa,rank数组快速的访问height数组,对于每一个询问向两边拓展,

【最小树形图(奇怪的kruskal)】【SCOI 2012】【bzoj 2753】滑雪与时间胶囊

2753: [SCOI2012]滑雪与时间胶囊 Time Limit: 50 Sec Memory Limit: 128 MB Submit: 1621 Solved: 570 Description a180285非常喜欢滑雪. 他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同一时候也是景点).并且每一个景点都有一编号i(1<=i<=N)和一高度Hi.a180285能从景点i 滑到景点j 当且仅当存在一条i 和j 之间的边,且i 的高度不小于j. 与其它滑雪爱好者不同,a1

【BZOJ】【2753】【SCOI2012】滑雪与时间胶囊

Kruskal/最小树形图 然而蒟蒻并不会做这题>_> 本来以为是有向图最小生成树,即最小树形图,但这数据范围有点…… 膜拜了zyf的题解:http://www.cnblogs.com/zyfzyf/p/4004236.html 题解:(摘自声亦香) 因为只能从高处到低处,所以无向边可以当有向边看待,然后按照题目意思就是给你一个有向图,求一个最小树形图,然后如果你用朱刘算法来算,就只能得到70分. 这道题具有与其余最小树形图不一样的地方:点有高度!难道高度只是拿来转化为有向边吗?当然不是. 回

BZOJ 2753 滑雪与时间胶囊(最短路-克鲁斯卡尔)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2753 题意:一个n个点m条边的带权无向图,每个点有一个高度值h.某个从1号点开始遍历,每次走的边u到v,必须满足h[u]>=h[v].已知从当前点回到曾经遍历过的任意一个点是不需要走路的.求最多可以遍历多少个点?遍历这些点走的最小路程是多少? 思路:只记录h[u]>=h[v]的 边,因为其他边是无用的,这样其实是个有向图.首先从1BFS一次可以得到多少个点可以到达.然后将边排序,对于

[BZOJ 2753][SCOI2012]滑雪与时间胶囊

Description a180285非常喜欢滑雪.他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i<=N)和一高度Hi.a180285能从景点i 滑到景点j 当且仅当存在一条i 和j 之间的边,且i 的高度不小于j. 与其他滑雪爱好者不同,a180285喜欢用最短的滑行路径去访问尽量多的景点.如果仅仅访问一条路径上的景点,他会觉得数量太少.于是a180285拿出了他随身携带的时间胶囊.这是一种很神奇的药物,吃下之后可以立即回到

bzoj 2753 滑雪与时间胶囊

2753: [SCOI2012]滑雪与时间胶囊 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 2006  Solved: 710[Submit][Status][Discuss] Description a180285非常喜欢滑雪.他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i<=N)和一高度Hi.a180285能从景点i 滑到景点j 当且仅当存在一条i 和j 之间的边,且i

CDOJ 42/BZOJ 2753 滑雪与时间胶囊 kruskal

2753: [SCOI2012]滑雪与时间胶囊 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 1376  Solved: 487[Submit][Status][Discuss] Description a180285非常喜欢滑雪.他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i<=N)和一高度Hi.a180285能从景点i 滑到景点j 当且仅当存在一条i 和j 之间的边,且i

2753: [SCOI2012]滑雪与时间胶囊

2753: [SCOI2012]滑雪与时间胶囊 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 2633  Solved: 910 Description a180285非常喜欢滑雪.他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i<=N)和一高度Hi.a180285能从景点i 滑到景点j 当且仅当存在一条i 和j 之间的边,且i 的高度不小于j. 与其他滑雪爱好者不同,a1802