zoukankan      html  css  js  c++  java
  • BZOJ 2753 [SCOI2012] 滑雪和时间胶囊 最小生成树

    题目链接:

    题目

    2753: [SCOI2012]滑雪与时间胶囊
    Time Limit: 50 Sec
    Memory Limit: 128 MB

    问题描述

    a180285非常喜欢滑雪。他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i<=N)和一高度Hi。a180285能从景点i 滑到景点j 当且仅当存在一条i 和j 之间的边,且i 的高度不小于j。 与其他滑雪爱好者不同,a180285喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。于是a180285拿出了他随身携带的时间胶囊。这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是a180285 滑行的距离)。请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。 现在,a180285站在1号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间
    胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?

    输入

    输入的第一行是两个整数N,M。
    接下来1行有N个整数Hi,分别表示每个景点的高度。
    接下来M行,表示各个景点之间轨道分布的情况。每行3个整数,Ui,Vi,Ki。表示
    编号为Ui的景点和编号为Vi的景点之间有一条长度为Ki的轨道。

    输出

    输出一行,表示a180285最多能到达多少个景点,以及此时最短的滑行距离总和。

    样例

    input
    3 3
    3 2 1
    1 2 1
    2 3 1
    1 3 10

    output
    3 2

    Hint

    【数据范围】
    对于30%的数据,保证 1<=N<=2000
    对于100%的数据,保证 1<=N<=100000
    对于所有的数据,保证 1<=M<=1000000,1<=Hi<=1000000000,1<=Ki<=1000000000。

    题解

    首先dfs一下,找到所有可达的点。
    然后发现是个最小树形图的问题,但是朱刘算法会跑超时!
    观察一下这道题的特殊性!
    我们按照海拔来分类,先讨论比较高的点再讨论比较低的点,你会发现同一个海拔的点之间连得都是双向边,所以同一个海拔的点是可以用kruskal跑最小生成树的。
    我们考虑两个相同海拔的连通,只能通过祖先或是同海拔的点,如果它们是通过后代来连通的话,那么它们之间必定是不连通的(有向边所导致的)所以我们对每条边先按终点的海拔降序排列,对相同的海拔按距离升序排序。然后跑kruskal最小生成树。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    const int maxm = 2e6 + 10;
    typedef long long LL;
    int n,m;
    
    int fa[maxn], hi[maxn];
    int find(int x) {
    	return fa[x] = fa[x] == x ? x : find(fa[x]);
    }
    
    
    struct Edge {
    	int u, v, w;
    	Edge(int u, int v, int w) :u(u), v(v), w(w) {}
    	bool operator < (const Edge& tmp) const {
    		return hi[v]>hi[tmp.v] || hi[v] == hi[tmp.v] && w < tmp.w;
    	}
    };
    
    vector<int> G[maxn];
    vector<Edge> egs, egs2;
    void addEdge(int u, int v, int w) {
    	egs.push_back(Edge(u, v, w));
    	G[u].push_back(egs.size() - 1);
    }
    
    int vis[maxn];
    void dfs(int u) {
    	for (int i = 0; i < G[u].size(); i++) {
    		Edge e = egs[G[u][i]];
    		egs2.push_back(e);
    		if (!vis[e.v]) {
    			vis[e.v] = 1;
    			dfs(e.v);
    		}
    	}
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; i++) scanf("%d", &hi[i]);
    	while (m--) {
    		int u, v,w;
    		scanf("%d%d%d", &u, &v,&w);
    		if (hi[u] < hi[v]) swap(u, v);
    		addEdge(u, v, w);
    		if (hi[u] == hi[v]) addEdge(v, u, w);
    	}
    	memset(vis, 0, sizeof(vis));
    	vis[1] = 1;
    	dfs(1);
    	sort(egs2.begin(), egs2.end());
    	for (int i = 1; i <= n; i++) fa[i] = i;
    	LL ans = 0; int cnt = 0;
    	for (int i = 0; i < egs2.size(); i++) {
    		Edge& e = egs2[i];
    		int pu = find(e.u);
    		int pv = find(e.v);
    		if (pu != pv) {
    			ans += e.w;
    			cnt++;
    			fa[pv] = pu;
    		}
    	}
    	printf("%d %lld
    ", cnt + 1, ans);
    	return 0;
    }
  • 相关阅读:
    【Gamma】 Phylab 展示博客
    【技术博客】Postman接口测试教程
    【技术博客】利用Python将markdown文档转为html文档
    【技术博客】使用PhpStorm和Xdebug实现Laravel工程的远程开发及调试
    【技术博客】Laravel5.1文件上传单元测试
    【技术博客】移动端的点击事件与Sticky Hover问题
    【技术博客】 Laravel 5.1单元测试(PHPUnit)入门
    Scrum Meeting博客目录
    团队事后分析
    Gamma阶段测试报告
  • 原文地址:https://www.cnblogs.com/fenice/p/5638926.html
Copyright © 2011-2022 走看看