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 }
  • 相关阅读:
    记第一场省选
    POJ 2083 Fractal 分形
    CodeForces 605A Sorting Railway Cars 思维
    FZU 1896 神奇的魔法数 dp
    FZU 1893 内存管理 模拟
    FZU 1894 志愿者选拔 单调队列
    FZU 1920 Left Mouse Button 简单搜索
    FZU 2086 餐厅点餐
    poj 2299 Ultra-QuickSort 逆序对模版题
    COMP9313 week4a MapReduce
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7470768.html
Copyright © 2011-2022 走看看