• (板子) 最小生成树 买礼物 luogu P1194


    luogu题目传送门!

    懒得找最小生成树模板了,就把这题当板子吧。

    最小生成树,就是指对于一张图,我们将图转换成一棵树,连通的,同时让所有的边尽可能的小(废话)。


    最小生成树一般都采用Kruskal算法,期间需要用到并查集。大体思路如下:

    先将所有边从小到大排序,对所有的节点维护并查集 f。

    然后依次遍历所有的边,(当然是先从小的开始)。可以将并查集的 f 理解为缩点的类似操作。如果一条边的两个点

    在同一个 f 中,则证明这两个点已经连通,不需要这条边(当然是前面通过别的小边已经连通了)。

    因此,在从小到大遍历边的时候,如果两个点不在一个集合,就连这条边(因为他小)。

    在同一个集合中,就不用画蛇添足了。

    再看这道(没人权的)题,如果把每个物品当作点,那么价格就是边权。如果有优惠,我们当然选择买优惠的。(虽然这道题数据毒瘤,居然还有

    优惠比原价高的情况,必须特判)

    没有优惠,就连原价。反正最后都会经过最小生成树的筛选。

    上板子代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define N 1000100
    #define isdigit(c) ((c)>='0'&&(c)<='9')
    #define orz 0
    
    inline int read(){
        int x = 0, s = 1;
        char c = getchar();
        while(!isdigit(c)){
            if(c == '-') s = -1;
            c = getchar();
        }
        while(isdigit(c)){
            x = (x << 1) + (x << 3) + (c ^ '0');
            c = getchar();
        }
        return x * s;
    } 
    
    struct node{
        int u, v, w;
    } t[N];
    int bian = 0;
    int fa[N];
    int ans = 0;
    
    int find(int x){
        return x == fa[x] ? x : fa[x] = find(fa[x]);
    }
    
    bool cmp (node a, node b){
        return a.w < b.w;
    }
    
    void kruskal(int pri, int n){
        for(int i = 1;i <= n; i++) fa[i] = i;
        sort(t + 1, t + bian + 1, cmp);
        for(int i = 1;i <= bian; i++){
            int u = t[i].u, v = t[i].v, w = t[i].w;
            int fau = find(u), fav = find(v);
            if(fau != fav){
                fa[fau] = fav;
                ans += (w < pri ? w : pri); /*毒瘤数据可能出现 w > pri 的情况,这种时候肯定选择 pri*/
            }
        }
        return ;
    } 
    
    int main(){
    //    freopen("hh.txt", "r", stdin);
        int pri = read(), n = read();  
        for(int i = 1;i <= n; i++){
            for(int j = 1;j <= n; j++){
                int x = read();
                if(x != 0){    /*注意给边去重!!*/
                    t[++bian].u = i;
                    t[bian].v = j;
                    t[bian].w = x;
                }
            }
        }
        kruskal(pri, n);
        for(int i = 1;i <= n; i++)
            if(fa[i] == i)ans += pri;  /*可能出现有的物品没有优惠或者是图中的第一个*/
        printf("%d
    ", ans);
        return orz; /*向dalao低头*/
    }
  • 相关阅读:
    端口被占用
    启动Windows防火墙提示“0x8007042c"
    vue创建全局组件
    vue中过度动画之列表添加删除动画实现
    vue中过渡动画(类名结合动画实现方式)
    vue中过渡动画(类名实现方式)
    this.$nextTick()方法的使用
    利用axios获取数据并渲染到视图层
    axios的简单使用
    watch深度监听
  • 原文地址:https://www.cnblogs.com/wondering-world/p/12718996.html
Copyright © 2020-2023  润新知