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

题目大意:在滑雪场中,每一个景点有一个高度。现在小明在一号节点。i和j之间有单向边当且仅当i的高度不高于j。问小明最多可以去多少个景点,和最小总费用。

思路:这是一道数学证明的好题。

第一问比较水,直接将可行的边连接起来,然后BFS出解。

第二问就比较难搞了。不难看出,直接用朱刘算法是不可行的,因为朱刘算法的时间复杂度达到了O(mn),而这个题至少需要一个O(mlogm)的算法。

恩?你说mlogm?难道是最小生成树?但是这图中都是单向边啊。

经过了上网找题解,和同学研究之后,终于弄明白了这题的精髓。简要说明一下做法和正确性。

做法很简单。只需要改变一下边的排序,第一键值为终点的高度,第二键值为边的权值。然后正常跑MST就行了。可这是为什么?

首先明确,在一个高度中,两点之间有边就一定是双向边。那么在一个高度且有边的点会形成一个强连通分量。将所有能够从1遍历到的点进行缩点之后,图会变成以1所在的SCC为起点的可拓扑图(因为高度比1还高的点一定无法到达,所以没有边)。

之后从上向下考虑,每一个SCC的高度一定是一样的。而终点为这个高度的边有两种,一种是从更高处的SCC连到这个高度的SCC的单向边,和这个SCC中的双向边,在处理这一层的时候,可以吧这两种边都看成是无向边,也就可以套用正常的MST了。

CODE:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 2000010
using namespace std;

int h[MAX];

struct Edge{
    int x,y,length;

    bool operator <(const Edge &a) const {
        if(h[y] == h[a.y])  return length < a.length;
        return h[y] > h[a.y];
    }
    void Read() {
        scanf("%d%d%d",&x,&y,&length);
        if(h[x] < h[y])  swap(x,y);
    }
}edge[MAX];

int points,edges;
int head[MAX],total;
int next[MAX],aim[MAX];

int father[MAX];
bool v[MAX];

inline void Add(int x,int y)
{
    next[++total] = head[x];
    aim[total] = y;
    head[x] = total;
}

int BFS()
{
    static queue<int> q;
    int re = 1;
    v[1] = true;
    q.push(1);
    while(!q.empty()) {
        int x = q.front(); q.pop();
        for(int i = head[x]; i; i = next[i])
            if(!v[aim[i]]) {
                v[aim[i]] = true;
                ++re;
                q.push(aim[i]);
            }
    }
    return re;
}

int Find(int x)
{
    if(father[x] == x)  return x;
    return father[x] = Find(father[x]);
}

long long MST()
{
    long long re = 0;
    sort(edge + 1,edge + edges + 1);
    for(int i = 1; i <= points; ++i) father[i] = i;
    for(int i = 1; i <= edges; ++i) {
        if(!v[edge[i].x] || !v[edge[i].y])  continue;
        int fx = Find(edge[i].x);
        int fy = Find(edge[i].y);
        if(fx != fy) {
            father[fx] = fy;
            re += edge[i].length;
        }
    }
    return re;
}

int main()
{
    cin >> points >> edges;
    for(int i = 1; i <= points; ++i)
        scanf("%d",&h[i]);
    for(int i = 1; i <= edges; ++i) {
        edge[i].Read();
        Add(edge[i].x,edge[i].y);
        if(h[edge[i].x] == h[edge[i].y])
            Add(edge[i].y,edge[i].x);
    }
    cout << BFS() << ' ';
    cout << MST() << endl;
    return 0;
}

时间: 2024-10-03 07:19:06

BZOJ 2753 SCOI 2012 滑雪与时间胶囊 最小生成树的相关文章

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算法的正确性证明 可以不妨设图中所有边的权重都不

bzoj2753[SCOI2012]滑雪与时间胶囊 最小生成树

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

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][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

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一次可以得到多少个点可以到达.然后将边排序,对于

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