[SCOI2012]滑雪与时间胶囊

Posted Z-Y-Y-S

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SCOI2012]滑雪与时间胶囊相关的知识,希望对你有一定的参考价值。

题目描述

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

输入输出格式

输入格式:

输入的第一行是两个整数N,MN,MN,M。

接下来111行有NNN个整数HiH_iH?i??,分别表示每个景点的高度。

接下来MMM行,表示各个景点之间轨道分布的情况。每行333个整数,Ui,Vi,KiU_i,V_i,K_iU?i??,V?i??,K?i??。表示编号为UiU_iU?i??的景点和编号为ViV_iV?i??的景点之间有一条长度为KiK_iK?i??的轨道。

输出格式:

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

输入输出样例

输入样例#1:
3 3 
3 2 1 
1 2 1 
2 3 1 
1 3 10 
输出样例#1:
3 2

说明

【数据范围】

对于30% 30\% 30%的数据,保证 1≤N≤2000 1 \le N \le 2000 1N2000

对于100% 100\% 100%的数据,保证 1≤N≤105 1 \le N \le 10^5 1N10?5??

对于所有的数据,保证 $ 1 \le M \le 10^6 , 1 \le H_i \le 10^9,1 \le K_i \le 10^9 $。

按照题目意思就是给你一个有向图,求一个最小树形图,然后如果你用朱刘算法来算,就只能得到70分

因为有神奇的胶囊,所以有向边又可以看成双向边

而且每个选中的景点可以从1用bfs求出数量cnt

可以保证一定有cnt那么多个

这道题的反向边只会在高度相同的点之间出现。如果把边先按终点高度排序为第一关键字,边长为第二关键字排序之后,就会保证优先到高点,同高点之间选小边,然后就不会出现反向的情况,所以可以用kruskal实现用O(mlog(m))的时间复杂度解决这道题。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 typedef long long lol;
 8 struct Edge
 9 {
10   int u,v;
11   lol w;
12 }e[2000001];
13 struct Node
14 {
15   int next,to;
16 }edge[2000001];
17 int set[100001],n,m,num,head[100001],cnt;
18 lol h[100001],ans;
19 bool vis[100001];
20 void add(int u,int v)
21 {
22   num++;
23   edge[num].next=head[u];
24   head[u]=num;
25   edge[num].to=v;
26 }
27 int find(int x)
28 {
29   if (set[x]!=x) set[x]=find(set[x]);
30   return set[x];
31 }
32 bool cmp(Edge a,Edge b)
33 {
34   if (h[a.v]!=h[b.v]) return h[a.v]>h[b.v];
35   return a.w<b.w;
36 }
37 void bfs()
38 {int i;
39   queue<int> Q;
40   Q.push(1);
41   vis[1]=1;
42   cnt=1;
43   while (Q.empty()==0)
44     {
45       int u=Q.front();
46       Q.pop();
47       for (i=head[u];i;i=edge[i].next)
48     {
49       int v=edge[i].to;
50       if (vis[v]==0)
51         {cnt++;
52           Q.push(v);
53           vis[v]=1;
54         }
55     }
56     }
57   cout<<cnt<< ;
58 }
59 int main()
60 {int i,j;
61   cin>>n>>m;
62   for (i=1;i<=n;i++)
63     scanf("%lld",&h[i]);
64   for (i=1;i<=m;i++)
65     {
66       scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w);
67       if (h[e[i].u]<h[e[i].v]) swap(e[i].u,e[i].v);
68       add(e[i].u,e[i].v);
69       if (h[e[i].u]==h[e[i].v]) add(e[i].v,e[i].u);
70     }
71   bfs();
72   sort(e+1,e+m+1,cmp);
73   for (i=1;i<=n;i++)
74     set[i]=i;
75   ans=0;j=0;
76   for (i=1;i<=m;i++)
77     {
78       if (vis[e[i].u]==0||vis[e[i].v]==0) continue;
79       int p=find(e[i].u);
80       int q=find(e[i].v);
81       if (p!=q)
82     {
83       set[p]=q;
84       ans+=e[i].w;
85       j++;
86       if (j==cnt-1) break;
87     }
88     }
89   cout<<ans;
90 }

 

以上是关于[SCOI2012]滑雪与时间胶囊的主要内容,如果未能解决你的问题,请参考以下文章

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

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

[SCOI2012]滑雪与时间胶囊

[SCOI 2012]滑雪与时间胶囊

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

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