5月1日 [SCOI2012]滑雪与时间胶囊 最小生成树

图片说明
思路:因为只能从高度高到高度低。那么边就是有向的。而且最后一定是一棵树。
第一问,直接dfs就可以了。标记可以到达的点。第二步,把这些点之间的边提出来。然后跑一个kruskal就可以了。边的排序:如果高度不一样,高度高的在前面,如果高度一样,边短的在前面。因为我们总是先访问高度高的边。如果直接按高度小的在前。这个样例:

3 3
3 2 1
1 3 2
1 2 8
2 3 4
就过不了
#include<bits/stdc++.h>
#define LL long long
using namespace std;

vector<vector<int> > v(1000005);
int h[1000005], vis[1000005], f[1000005], cut=0;
struct E{
    int u, v, k;
}e[2000005];

void DFS(int u){
    vis[u]=1;
    for(int i=0; i<v[u].size(); i++){
        int to=v[u][i];
        if(!vis[to]&&h[u]>=h[to]){
            DFS(to); cut++;
        }
    }
}

int fd(int x){
    return (f[x]==x)?x:f[x]=fd(f[x]);
}

int main(){
    int n, m; scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++){
        scanf("%d", &h[i]); f[i]=i;
    }
    int x, y, k;
    for(int i=1; i<=m; i++){
        scanf("%d%d%d", &x, &y, &k);
        v[x].push_back(y);
        v[y].push_back(x);
        e[i]={x, y, k};
    }
    DFS(1);
    int tot=0;
    for(int i=1; i<=m; i++){
        x=e[i].u, y=e[i].v;
        if(vis[x]&&vis[y]){
            if(h[x]>=h[y]){
                e[++tot]=e[i];
            }
            else{
                e[++tot]=e[i];
                swap(e[tot].u, e[tot].v);
            }
        }
    }
    sort(e+1, e+1+tot, [](E &a, E &b){ return a.k<b.k;});
    LL ans=0;
    for(int i=1; i<=tot; i++){
        x=fd(e[i].u), y=fd(e[i].v);
        if(x!=y){
            f[x]=y; ans+=e[i].k;
        }
    }
    printf("%d %lld\n", cut+1, ans);

    return 0;
}
全部评论

相关推荐

11-11 14:21
西京学院 C++
无敌混子大王:首先一点,不管学校层次怎么样,教育经历放在第一页靠上位置,第一页看不到教育经历,hr基本直接扔掉了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务