zoukankan      html  css  js  c++  java
  • [SCOI2012]滑雪与时间胶囊

    题目描述

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

    输入输出格式

    输入格式:

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

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

    接下来MMM行,表示各个景点之间轨道分布的情况。每行333个整数,Ui,Vi,KiU_i,V_i,K_iUi​​,Vi​​,Ki​​。表示编号为UiU_iUi​​的景点和编号为ViV_iVi​​的景点之间有一条长度为KiK_iKi​​的轨道。

    输出格式:

    输出一行,表示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 1N105​​

    对于所有的数据,保证 $ 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 }
  • 相关阅读:
    USACO Grass Planting
    洛谷 P3178 [HAOI2015]树上操作
    史上最全NOIP初赛知识点
    史上最全的CSP-J/S 第一轮知识点
    洛谷 P1886 滑动窗口
    背包九讲—简单背包
    NOIP 2005 采药
    洛谷 P2357 守墓人
    NOI 2015 软件包管理器
    洛谷 P3384 【模板】树链剖分
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7470768.html
Copyright © 2011-2022 走看看