SCOI 2012 滑雪与时间胶囊

题目:http://61.187.179.132/JudgeOnline/problem.php?id=2753

Description

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

Input

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

Output

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

Sample Input


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

Sample Output

3 2

HINT

 

【数据范围】 

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

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

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

 
题解:
  题目的意思就是首先找到从编号为一的点开始走,能走的一定是高度不高于它的点,然后得到一个点集,把边加进去后得到一张新图,求这个图的最小树形图即可了。
 
  题意如此简单………………利用了该题的某些神奇性质………………把边按终点的高度为第一关键字,边长为第二关键字,排个序后就可以做了…………………………注意答案要64为整数即可…………………………
 
View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 
 7 using namespace std;
 8 
 9 const int maxn=100001;
10 const int maxm=2000001;
11 
12 int sum,en,h[maxn],f[maxn],n,m;
13 
14 long long ans;
15 
16 bool use[maxn];
17 
18 queue<int> que;
19 
20 struct edge
21 {
22        int s,e,d;
23        edge *next;
24 }*v[maxn],ed[maxm];
25 
26 void add_edge(int s,int e,int d)
27 {
28      en++;
29      ed[en].next=v[s];v[s]=ed+en;v[s]->s=s;v[s]->e=e;v[s]->d=d;
30 }
31 
32 void bfs()
33 {
34      use[1]=true;
35      sum=1;
36      que.push(1);
37      f[1]=1;
38      while (que.size())
39      {
40            int now=que.front();
41            que.pop();
42            for (edge *e=v[now];e;e=e->next)
43                if (!use[e->e])
44                {
45                               f[e->e]=e->e;
46                               use[e->e]=true;
47                               sum++;
48                               que.push(e->e);
49                }
50      }
51 }
52 
53 bool cmp(edge a,edge b)
54 {
55      return h[a.e]>h[b.e] || (h[a.e]==h[b.e] && a.d<b.d);
56 }
57 
58 int getf(int now)
59 {
60     return (f[now]==now)?now:f[now]=getf(f[now]);
61 }
62 
63 int main()
64 {
65     freopen("ski.in","r",stdin);
66     freopen("ski.out","w",stdout);
67     
68     scanf("%d%d",&n,&m);
69     for (int a=1;a<=n;a++)
70         scanf("%d",&h[a]);
71     for (int a=1;a<=m;a++)
72     {
73         int x,y,d;
74         scanf("%d%d%d",&x,&y,&d);
75         if (h[x]>=h[y]) add_edge(x,y,d);
76         if (h[y]>=h[x]) add_edge(y,x,d);
77     }
78     bfs();
79     sort(ed+1,ed+en+1,cmp);
80     for (int a=1;a<=n;a++)
81     f[a]=a;
82     for (int a=1;a<=en;a++)
83     {
84         if (!use[ed[a].s] || !use[ed[a].e]) continue;
85         int s=ed[a].s,e=ed[a].e;
86         int fx=getf(s),fy=getf(e);
87         if (fx!=fy)
88         {
89                    ans=ans+ed[a].d;
90                    f[fx]=fy;
91         }
92     }
93     printf("%d %lld\n",sum,ans);
94     
95     return 0;
96 }
原文地址:https://www.cnblogs.com/zhonghaoxi/p/2490889.html