zoukankan      html  css  js  c++  java
  • Applese 的毒气炸弹 G 牛客寒假算法基础集训营4(图论+最小生成树)

    链接:https://ac.nowcoder.com/acm/contest/330/G
    来源:牛客网

    Applese 的毒气炸弹
    时间限制:C/C++ 2秒,其他语言4秒
    空间限制:C/C++ 262144K,其他语言524288K
    64bit IO Format: %lld

    题目描述


    众所周知,Applese 是个很强的选手,它的化学一定很好。

    今天他又AK了一套题觉得很无聊,于是想做个毒气炸弹玩。

    毒气炸弹需要 k 种不同类型元素构成,Applese一共有 n 瓶含有这些元素的试剂。

    已知元素混合遵循 m 条规律,每一条规律都可以用 "x y c" 描述。

    表示将第 x 瓶试剂混入第 y 瓶试剂或者把第 y 瓶试剂混入第 x 瓶试剂,需要消耗 c 的脑力。

    特别地,除了这 m 条规律外,Applese 可以将任意两瓶相同元素的试剂混合,且不需要消耗脑力。

    Applese 想要配出毒气炸弹,就需要使 S 中含有 1k1∼k 这 k 种元素。它想知道自己最少花费多少脑力可以把毒气炸弹做出来。

    输入描述:

    第一行为三个整数 n, m, k 表示 Applese 拥有的试剂的数量,混合规律的数量和所需的元素种类数。
    第二行为 n 个整数 a1,a2,,ana1,a2,…,an,分别表示每一瓶试剂的元素类型。
    接下来m行,每行三个整数 x, y, c,含义如题目描述中所述。不保证 x, y的试剂种类不同。

    输出描述:

    输出一个正整数表示最小的耗费脑力。特别地,如果无法合成出毒气炸弹,输出 "-1"。
    示例1

    输入

    复制
    6 8 2
    1 1 1 2 2 2
    1 2 1
    2 3 2
    1 3 3
    3 4 6
    4 5 1
    4 6 3
    5 6 2
    1 6 2

    输出

    复制
    2

    备注:

    1n,k,m1051≤n,k,m≤105
    1x,yn,xy1≤x,y≤n,x≠y
    1c109


    思路:
    看成一张图,就是把同类元素的试剂当作一个点之后,求这个图的最小生成树。
    然后用你最喜欢的求MST的算法求解就好。注意判不连通的情况。

    细节见代码
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #define rt return
    #define sz(a) int(a.size())
    #define all(a) a.begin(), a.end()
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define pii pair<int,int>
    #define pll pair<long long ,long long>
    #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    #define MS0(X) memset((X), 0, sizeof((X)))
    #define MSC0(X) memset((X), '', sizeof((X)))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define eps 1e-6
    #define gg(x) getInt(&x)
    #define db(x) cout<<"== [ "<<x<<" ] =="<<endl;
    using namespace std;
    typedef long long ll;
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
    ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
    inline void getInt(int* p);
    const int maxn=1000010;
    const int inf=0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    struct Edge
    {
        int f,t,w;
        Edge(){}
        Edge(int ff,int tt,int ww)
        {
            f=ff;
            t=tt;
            w=ww;
        }
    };
    std::vector<Edge> edge;
    bool cmp(Edge a,Edge b)
    {
        return a.w<b.w;
    }
    // 并查集部分
    int fa[maxn];
    int findpar(int x)
    {
        if(fa[x]==x)
            return x;
        else
            return fa[x]=findpar(fa[x]);
    }
    void initufs(int n)
    {
        repd(i,1,n)
        {
            fa[i]=i;
        }
    }
    int n,m,k; // 
    int a[maxn];
    ll Kruskal()
    {
        ll res=0ll;
        initufs(n);
        int cnt=0;// 记录了MST加入了几个节点
        for(int i=0;i<edge.size();i++)
        {
            int u=findpar(edge[i].f);
            int v=findpar(edge[i].t);
            if(u==v)
                continue;
            fa[u]=v; // merge
            res+=edge[i].w;
            cnt++;
            if(cnt==k-1) // 已经加满了树
                break;
        }
        if(cnt!=k-1)
            return -1;
        else
            return res;
    }
    int main()
    {
        scanf("%d %d %d",&n,&m,&k);
        repd(i,1,n)
        {
            scanf("%d",&a[i]);
        }    
        int u,v,w;
        repd(i,1,m)
        {
            scanf("%d %d %d",&u,&v,&w);
            u=a[u];v=a[v];
            if(u==v)
                continue;
            if(u>=1&&u<=k&&v>=1&&v<=k)
            {
                edge.push_back(Edge(u,v,w));
            }
    
        }
        sort(edge.begin(),edge.end(),cmp);
        ll res=Kruskal();
        printf("%lld
    ",res );
        return 0;
    }
    
    inline void getInt(int* p) {
        char ch;
        do {
            ch = getchar();
        } while (ch == ' ' || ch == '
    ');
        if (ch == '-') {
            *p = -(getchar() - '0');
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 - ch + '0';
            }
        }
        else {
            *p = ch - '0';
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 + ch - '0';
            }
        }
    }
     

    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    机器学习经典聚类算法 —— k-均值算法(附python实现代码及数据集)
    机器学习经典分类算法 —— k-近邻算法(附python实现代码及数据集)
    linux进程间通信之消息队列
    Linux下的权限掩码umask
    AVL树的插入操作(旋转)图解
    二叉搜索树的插入与删除图解
    MySQL密码忘记之解决方法
    C++之类的构造函数,不得不学明白的重点
    C++编译器的函数名修饰规则
    递归和尾递归的比较,斐波那契
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/10336421.html
Copyright © 2011-2022 走看看