CODEVS 2399 滑雪与时间胶囊

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

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

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

数据范围及提示 Data Size & Hint
对于30%的数据,保证 1<=N<=2000
对于100%的数据,保证 1<=N<=100000
对于所有的数据,保证 1<=M<=1000000,1<=Hi<=1000000000,1<=Ki<=1000000000。

%%%红太阳。
下午想找一道比较好的最小生成树的题,然后红太阳就给我安利了这道。

为什么说是最小生成树呢?
时间胶囊吃下之后可以立即回到上个经过的景点
我们需要遍历这张图的某些节点,我们走到一个节点…吃下胶囊回去了,重复这个过程,直到遍历完所有的节点,假设我们遍历了n个点,最好情况下是走了n-1条边,为了让总路程尽量小,这不就是最小生成树么?
从景点i滑到景点j当且仅当存在一条 i和 j之间的边,且 i的高度不小于j
不 小 于
所以两个点之间距离相等也是可以建边的啊。

对于第一问,我们建好了边以后直接从一号点跑DFS,每跑到一个点,答案就++。
我们一定能到达这个DFS中所到达的点。

那么对于第二问。
再来看看题。
他十分想知道在不考虑时间胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)

所以我们首先要保证能滑到尽量多的景点啊。
所以,对于每次到达一个景点,它的高度越高越好。
所以sort里面的cmp函数就要这么写辣。
我们以每条边到达的点按高度大小 从大到小排序,如果两个点高度相等的话,就把权值小的排在前面。

bool cmp(meico a,meico b)
{
    if(high[a.to]==high[b.to])
    return a.d<b.d;
    return high[a.to]>high[b.to];
}

这个题还有个坑点,就是时限和数据范围….看着这一坨零就让人不想做好嘛= =,还有BZOJ上这个题时限是50s是什么意思?

#include<algorithm>
#include<cstring> 
#include<cstdio>
#include<queue>
#define maxn 1000000*2+50
using namespace std;
typedef long long ll;

void read(int &a)
{
    char c=getchar();
    while(c>'9'||c<'0')
        c=getchar();
    int ans=0;
    while(c<='9'&&c>='0')
        ans*=10,ans+=c-'0',c=getchar();
    a=ans;
    return;
}
void readl(ll &a)
{
    char c=getchar();
    while(c>'9'||c<'0')
        c=getchar();
    ll ans=0;
    while(c<='9'&&c>='0')
        ans*=10,ans+=c-'0',c=getchar();
    a=ans;
    return;
}
struct Edge
{
    int f;
    int to;
    ll d;
    int next;
}edge[maxn];
struct meico
{
    int f;
    int to;
    ll d;
}sz[maxn];
ll high[maxn];
int tott;
int head[maxn];
void add1(int f,int t,ll d)
{
    edge[++tott]=(Edge){f,t,d,head[f]};
    sz[tott]=(meico){f,t,d};
    head[f]=tott;
}
int n,m;
bool vis[maxn];
bool cmp(meico a,meico b)
{
    if(high[a.to]==high[b.to])
    return a.d<b.d;
    return high[a.to]>high[b.to];
}
int fa[maxn];
int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
int ans1;
void dfs(int f,int t)
{
    vis[t]=1;
    ans1++;
    for(int i=head[t];i;i=edge[i].next)
    {
        Edge e=edge[i];
        if(!vis[e.to])
            dfs(t,e.to);
    } 
}

void K()
{
    sort(sz+1,sz+tott+1,cmp);
    int tot=0;
    ll ans=0;
    for(int i=1;i<=tott;i++)
    {
        meico m=sz[i];
        if(!vis[m.f]||!vis[m.to])
            continue;
        int x=find(m.f);
        int y=find(m.to);
        if(x!=y)
        {
            fa[x]=y;
            ans+=m.d;
        }
    }
    printf("%lld",ans);
}
int main()
{
    read(n),read(m);
    for(int i=1;i<=n;i++)
        readl(high[i]),fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        int a,b;
        ll c;
        read(a),read(b),readl(c);
        if(high[a]>=high[b])
            add1(a,b,c);
        if(high[a]<=high[b])
            add1(b,a,c);
    }
    dfs(1000005,1);
    printf("%d ",ans1); 
    K();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值