洛谷 P2573 [SCOI2012]滑雪

题目描述

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最多能到达多少个景点,以及此时最短的滑行距离总和。

输入输出样例

输入样例#1:

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

输出样例#1:

3 2

说明

【数据范围】

对于30%的数据,保证 1<=N<=2000

对于100%的数据,保证 1<=N<=100000

对于所有的数据,保证 1<=M<=1000000,1<=Hi<=1000000000,1<=Ki<=1000000000。

这题目的题意真是看不懂

大概意思是给出一张有向图,边的方向是从高到低,让你求一个最小树形图

朱刘算法怒艹1e13也不是不可以啊

这道题的思路确实很妙,没看题解想不到

首先观察发现能到达的点就是一遍BFS,这些点肯定都要到达

然后走过的路径是一个以1为根的最小树形图

直接朱刘算法肯定不行,需要考虑别的办法

这张图的的性质是边只从高连向低,同高度之间是无向边

如果把点按照高度分层,那么有向边只从高的一层连向低的一层,层内只有无向边

这有什么用呢?

我们知道,对于无向图的树形图(即生成树),有很优秀的办法来解决,为什么kruskal和prim不能做有向图的树形图呢?稍微尝试几个例子以后会发现,如果用无向图的方法来做,会有两个问题

1、答案不是最优,这是由于prim的加入顺序问题导致的

2、做出来的根本不是树形图,kruskal没法处理这种情况

但是对于DAG这种特殊的图而言,无向图的方法加上一些魔改就可以做了,对于kruskal而言,把边按照终点的拓扑序为第一关键字,边长为第二关键字排序,然后往里加就行了

让我们回到这道题的图,我们发现这张图很像是一层层的DAG加上层内的无向图,是不是胡搞一下就好了啊?

发现是的,一样这么做就行,第一关键字h降序,第二关键字变长升序,原因是这样既不会产生第一个问题(按顺序一层层加入,答案不会变劣),也不会产生第二个问题(层间不会有问题,层内是无向边,可以随意分配)

然后跑kruskal即可

  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <algorithm>
  5 #include <string>
  6 #include <cstring>
  7 #include <cmath>
  8 #include <map>
  9 #include <stack>
 10 #include <set>
 11 #include <vector>
 12 #include <queue>
 13 #include <time.h>
 14 #include <functional>
 15 #define eps 1e-7
 16 #define INF 0x3f3f3f3f
 17 #define MOD 1000000007
 18 #define rep0(j,n) for(int j=0;j<n;++j)
 19 #define rep1(j,n) for(int j=1;j<=n;++j)
 20 #define pb push_back
 21 #define set0(n) memset(n,0,sizeof(n))
 22 #define ll long long
 23 #define ull unsigned long long
 24 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt)
 25 #define max(a,b) (a>b?a:b)
 26 #define min(a,b) (a<b?a:b)
 27 #define print_runtime printf("Running time:%.3lfs\n",double(clock())/1000.0)
 28 #define TO(j) printf(#j": %d\n",j);
 29 //#define OJ
 30 using namespace std;
 31 const int MAXINT = 100010;
 32 const int MAXNODE = 100010;
 33 const int MAXEDGE = 4 * 1000010;
 34 char BUF, *buf;
 35 int read() {
 36     char c = getchar(); int f = 1, x = 0;
 37     while (!isdigit(c)) {if (c == ‘-‘) f = -1; c = getchar();}
 38     while (isdigit(c)) {x = x * 10 + c - ‘0‘; c = getchar();}
 39     return f * x;
 40 }
 41 char get_ch() {
 42     char c = getchar();
 43     while (!isalpha(c)) c = getchar();
 44     return c;
 45 }
 46 //------------------- Head Files ----------------------//
 47 int cnt, n, m;
 48 int vis[MAXNODE],ans,h[MAXNODE],qu[MAXNODE],fa[MAXNODE];
 49 struct edge {
 50     int u, v, l;
 51     edge *nxt;
 52     edge(int _u, int _v, int _l, edge * _nxt): u(_u), v(_v), l(_l), nxt(_nxt) {}
 53     edge() {}
 54 } mp[MAXEDGE], *head[MAXNODE];
 55 bool operator < (const edge &a,const edge &b){
 56     return h[a.v]==h[b.v]?a.l<b.l:h[a.v]>h[b.v];
 57 }
 58 void get_input();
 59 void work();
 60 void addedge(int u, int v,int l) {
 61     mp[cnt] = edge(u, v, l,head[u]);
 62     head[u] = &mp[cnt++];
 63 }
 64 /*void spfa(int ss, int tt) {
 65     memset(dis, 0x3f, sizeof(dis));
 66     dis[ss] = 0;
 67     int *h, *t;
 68     h = t = q;
 69     *t++ = ss;
 70     while (h != t) {
 71         int p = *h++; inq[p] = 0;
 72         iter(i, p) {
 73             if (dis[i->v] > dis[p] + i->l) {
 74                 dis[i->v] = dis[p] + i->l;
 75                 if (!inq[i->v]) {
 76                     *t++ = i->v;
 77                     inq[i->v] = 1;
 78                 }
 79             }
 80         }
 81     }
 82 }*/
 83 /*void dijkstra(int ss,int tt){
 84     memset(dis,0x3f,sizeof(dis));
 85     dis[ss]=0;
 86     q.push(make_pair(0,ss));
 87     int T=n-1;
 88     while(T--){
 89         while(!q.empty()&&vis[q.top().second]) q.pop();
 90         if(q.empty()) break;
 91         int p = q.top().second;q.pop();
 92         iter(i,p){
 93             if(dis[i->v]>dis[p]+i->l){
 94                 dis[i->v]=dis[p]+i->l;
 95                 q.push(make_pair(dis[i->v],i->v));
 96             }
 97         }
 98     }
 99 }*/
100 void bfs(int p){
101     int *h,*t;
102     h=t=qu;
103     vis[1]=1;ans=1;
104     *t++=1;
105     while(h!=t){
106         int p=*h++;
107         iter(i,p){
108             if(!vis[i->v]) {vis[i->v]=1;ans++;*t++=i->v;}
109         }
110     }
111 }
112 int findfa(int p) {return p==fa[p]?p:fa[p]=findfa(fa[p]);}
113 int main() {
114     get_input();
115     work();
116     return 0;
117 }
118 void work() {
119     //dijkstra(1,n);
120     bfs(1);
121     rep1(i,n) fa[i]=i;
122     sort(mp,mp+cnt);
123     ull sum=0;
124     rep0(i,cnt){
125         int u=mp[i].u,v=mp[i].v;
126         if(!vis[u]||!vis[v]) continue;
127         u=findfa(u);v=findfa(v);
128         if(u!=v) {fa[u]=v; sum+=mp[i].l;}
129     }
130     printf("%d %llu\n",ans,sum);
131 }
132 void get_input() {
133     n = read(); m = read();
134     rep1(i, n) h[i] = read();
135     rep0(i, m) {
136         int u = read(), v = read(), l = read();
137         if (h[u] > h[v]) addedge(u, v, l);
138         if (h[u] == h[v]) {addedge(u, v, l); addedge(v, u, l);}
139         if (h[u] < h[v]) addedge(v, u, l);
140     }
141
142 }
时间: 2024-10-03 14:30:01

洛谷 P2573 [SCOI2012]滑雪的相关文章

洛谷 P2336 [SCOI2012]喵星球上的点名

题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 N 个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M 个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到. 然而,由于喵星人的字码过于古怪,以至于不能用 ASCII 码来表示.为了方便描述,a180285 决定用数串来表示喵星人的名字. 现在你能帮助 a180285 统计每次点名的时候有多少喵星人答到,以及 M 次点名结

P2573 [SCOI2012]滑雪

题目链接 在题中每个点都有一个限制条件,对于一个点,只能通向高度低于它的点,所以我们可以对题目中的所有点建有向图.然后可以从1开始通过bfs找到所有可以通向的点. 找到了这些点过后又怎么办呢?题目中说要使得经过最多景点数的点的边权值最小.所以我们能够在bfs的同时将这些能够到达的点都建一个新的图.然后从1开始在这个新图上跑:kruskal即可求出最小的权值. 代码如下: #include<bits/stdc++.h> using namespace std; const int maxn=1e

【题解】Luogu P2573 [SCOI2012] 滑雪 最小生成树

并查集写错少find了导致一直MLE... dfs+kruskal 因为时间胶囊无限,所以相当于回溯回祖先节点再向下dfs 先dfs一遍看最多能滑多少点,能滑到的点连边 用这些新的边跑最小生成树,排序的时候先按高度从大到小再按边权从小到大 code 1 #include<bits/stdc++.h> 2 using namespace std; 3 namespace gengyf{ 4 const int maxn=1e5+5; 5 #define int long long 6 inlin

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

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

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

洛谷1231 教辅的组成

洛谷1231 教辅的组成 https://www.luogu.org/problem/show?pid=1231 题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题.然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册.已知一个完整的书册均应该包含且仅包含一本书.一本练习册和一份答案,然而现在全都乱做了一团.许多书上面的字迹都已经模糊了,然而HansBug还是可

洛谷教主花园dp

洛谷-教主的花园-动态规划 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树的高度分别为10,20,30.教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高. 输入输出格式 输入格式: 输入文件garden.in的第1行为一个正整数n,表示需要种的

洛谷 P2801 教主的魔法 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不

洛谷P1466 集合 Subset Sums

洛谷P1466 集合 Subset Sums这题可以看成是背包问题 用空间为 1--n 的物品恰好填充总空间一半的空间 有几种方案 01 背包问题 1.注意因为两个交换一下算同一种方案,所以最终 要 f [ v ] / 2 2.要开 long long 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string&g