zoukankan      html  css  js  c++  java
  • 滑雪与时间胶囊 题解 BZOJ2753

    真是受不了啊~~~

    说好的NOIP”摸你赛“结果出了个四川省选的题。。。。。。。然后,就没有然后了

    不说了,上题目!

    [SCOI2012]滑雪与时间胶囊

    Description

    a180285 非常喜欢滑雪。他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i& lt;=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。

    好了,不知道你看到这里还受不受得了,反正我受不了了。

    摆明了一道最小树形图的题,他丫的1后面这么多0的数据范围即便是3秒时限也是很难容忍的。

    所以,我们不得不选取一种新的方式来解决问题。

    转化思想是我们必须的思想,然而~~能不能转化出来,就要看个人的功力了。

    这 个题上午模拟赛的时候自己已经想到了有向最小生成树,而且打了一个左偏堆优prim来水,从1号雪山开始有向的向外扩展,样例可以过,然后就喜大普奔的打 了个左偏堆优prim出来(你可能会问我为什么用左偏堆(也叫左堆,左偏树),我会很都比的告诉你:不是因为快,而是因为二叉堆我不会打。。。。。。)

    好了废话不说了,prim实际上在这个题里有一个不小的BUG,因为我们用prim向外扩展的时候不会像三角形不等式一样更新我们之前已经记录过的值,所以在有向图中,会出现正着过不去,反着能回来但是不更新我们之前的值的情况。。。。。。。

    不太好理解,不过确实是不对,可以举出反例。

    3 3

    3 2 1

    1 2 7

    2 3 1

    1 3 5

    这样的话用prim得出的结论是5+7=12,而实际上,我们可以先到2号点,再从二号到3号。这样答案就是最优解7+1=8;

    那么正解呢?

    正解采用的是kruscal。为什么呢,因为我们对边进行某种排序之后能够保证先到高出再到低处,先走小的再走大的。这样的话就不会出现上面那种更新不到的情况了。

    所以我们对边进行双关键字排序:我们把边到达的点高度高的排在前面。高度相同的情况下,优先选边长较小的。

    这样我们就能保证我们先找到海拔较高的点然后再顺势而下到低点更新。

    还有一件事:建边

    如果连接的两个点海拔相同,那么双向建,high[s]>high[t]正向建,high[s]<high[t]反向建。

    好了,别忘了开long long,我手残建边开long long,ans用了int,所以WA了3遍。。。。

    AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #define INF 970232024
      6 #include<queue>
      7 using namespace std;
      8 struct edge
      9 {
     10     int s,t,next;
     11     long long w;
     12 }ed[2000020];
     13 int tot=0;
     14 int ans=0;
     15 int head[1000020];
     16 int high[1000020];
     17 long long dis[1000020];
     18 int n,m;
     19 void add(int s,int t,int w)
     20 {
     21     ed[tot].s=s; ed[tot].t=t; ed[tot].w=(long long)w; ed[tot].next=head[s]; head[s]=tot++;
     22 }
     23 bool cmp(edge a,edge b)
     24 {
     25     if(high[a.t]==high[b.t])
     26     {
     27         return a.w<b.w;
     28     }
     29     else return high[a.t]>high[b.t];
     30 }
     31 bool vis[1000020];
     32 int cnt;
     33 int f[1000020];
     34 bool need[1000020];
     35 bool inq[1000010];
     36 int find(int x)
     37 {
     38     if(f[x]==x)return x;
     39     return f[x]=find(f[x]);
     40 }
     41 void kruscal()
     42 {
     43     sort(ed,ed+tot-1,cmp);
     44   //  for(int i=0;i<tot;i++)cout<<ed[i].s<<" "<<ed[i].t<<" "<<ed[i].w<<endl;
     45     for(int i=0;i<tot;i++)
     46     {
     47         int x=ed[i].s;
     48         int y=ed[i].t;
     49         int f1=find(x);
     50         int f2=find(y);
     51         if(f1!=f2 && need[x] && need[y])
     52         {
     53             ans+=ed[i].w;
     54             f[f1]=f2;
     55         }
     56     }
     57 }
     58 int main()
     59 {
     60  //   freopen("ski.in","r",stdin);
     61  //   freopen("ski.out","w",stdout);
     62     memset(head,-1,sizeof head);
     63     scanf("%d%d",&n,&m);
     64     for(int i=1;i<=n;i++)
     65     {
     66         f[i]=i;
     67         dis[n]=INF;
     68         scanf("%d",&high[i]);
     69     }
     70     while(m--)
     71     {
     72         int a,b;
     73         long long c;
     74         scanf("%d%d%lld",&a,&b,&c);
     75         if(high[a]>high[b])add(a,b,c);
     76         else if(high[a]==high[b])
     77         {
     78             add(a,b,c);
     79             add(b,a,c);
     80         }
     81         else add(b,a,c);
     82     }
     83     queue<int> q;
     84     q.push(1);
     85     while(!q.empty())
     86     {
     87         int x=q.front();
     88         q.pop();vis[x]=true;
     89         for(int i=head[x];i!=-1;i=ed[i].next)
     90         {
     91             if(!vis[ed[i].t])
     92             {
     93                 q.push(ed[i].t);
     94             }
     95         }
     96     }
     97     for(int i=1;i<=n;i++)
     98     {
     99         if(vis[i])
    100         {
    101             cnt++;
    102             need[i]=true;
    103         }
    104     }
    105     cout<<cnt<<" ";
    106     memset(vis,false,sizeof vis);
    107     kruscal();
    108     cout<<ans<<endl;
    109 }
    View Code
  • 相关阅读:
    RIFF格式简介
    获取控制台窗口句柄GetConsoleWindow
    控制台编程基础总结
    控制台访问权限、别名及注意事项
    控制台输入输出机制实例
    控制台输入输出机制
    控制台基础概念实例
    STL之std::set、std::map的lower_bound和upper_bound函数使用说明
    wcout输出中文不显示
    控制台基础概念
  • 原文地址:https://www.cnblogs.com/Skyvot/p/4036459.html
Copyright © 2011-2022 走看看