zoukankan      html  css  js  c++  java
  • vijos P1234口袋的天空(Kruskal)(最小生成树)

    P1234口袋的天空

    小杉坐在教室里,透过口袋一样的窗户看口袋一样的天空。

    有很多云飘在那里,看起来很漂亮,小杉想摘下那样美的几朵云,做成棉花糖。

    描述

    给你云朵的个数N,再给你M个关系,表示哪些云朵可以连在一起。

    现在小杉要把一些云朵连在一起,做成K个棉花糖,一个棉花糖最少要用掉一朵云,小杉想知道他怎么连,花费的代价最小。

    格式

    输入格式

    每组测试数据的
    第一行有三个数N,M,K(1<=N<=1000,1<=M<=10000,1<=K<=10)
    接下来M个数每行三个数X,Y,L,表示X云和Y云可以通过L的代价连在一起。(1<=X,Y<=N,0<=L<10000)
    30%的数据N<=100,M<=1000

    输出格式

    对每组数据输出一行,仅有一个整数,表示最小的代价。

    如果怎么连都连不出K个棉花糖,请输出'No Answer'。

    样例1

    样例输入1[复制]

    3 1 2
    1 2 1

    样例输出1[复制]

    1

    限制

    每个测试点1s

    提示

    样例2:
    Input:
    3 1 1
    1 2 1

    Output:
    No Answer

    【分析】这个最小生成树题很有意思,他要求K个最小生成树,因为共有n朵云并且一朵云就可以构成一个棉花糖,所以不用云构造花费为0,那么就要留出k-1朵云单独作为一个棉花糖,即将剩下的n-(k-1)朵云构造 成一棵最小生成树,即当加入的边数=n-(k-1)-1时构造完成。此时构造的为最小生成树,构造这个棵树花费最小,其他花费为0,所以这样就以最小的花 费构造出了k个棉花糖;
    算法以并查集优化的kruscal来构造即可。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <climits>
    #include <cstring>
    #include <string>
    #include <set>
    #include <map>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <list>
    #include<functional>
    #define mod 1000000007
    #define inf 0x3f3f3f3f
    #define pi acos(-1.0)
    using namespace std;
    typedef long long ll;
    const int N=1005;
    
    struct Edg
    {
        int v,u;int w;
    }edg[300*300+50];
    bool cmp(Edg g,Edg h)
    {
        return g.w<h.w;
    }
    int n,m,k,cnt=1,maxn;
    int parent[N];
    void init()
    {
        for(int i=0;i<n;i++)parent[i]=i;
    }
    void Build()
    {
        int u,v,w;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            edg[i].u=u;edg[i].v=v;edg[i].w=w;
        }
        if(n<k){printf("No Answer
    ");exit(0);}
        sort(edg,edg+m,cmp);
    }
    int Find(int x) {
        if(parent[x] != x) parent[x] = Find(parent[x]);
        return parent[x];
    }//查找并返回节点x所属集合的根节点
    void Union(int x,int y) {
        x = Find(x);
        y = Find(y);
        if(x == y) return;
        parent[y] = x;
    }//将两个不同集合的元素进行合并
    void Kruskal()
    {
        int sum=0;
        int num=0;
        int u,v;
        for(int i=0;i<m;i++)
        {
            u=edg[i].u;v=edg[i].v;
            if(Find(u)!=Find(v))
            {
                sum+=edg[i].w;
    
                num++;
                Union(u,v);
            }
            if(num>=n-(k-1)-1){
                 printf("%d
    ",sum);
                 break;
            }
        }
        if(num<n-(k-1)-1)printf("No Answer
    ");
    }
    int main() {
            scanf("%d%d%d",&n,&m,&k);
            init();
            Build();
            Kruskal();
        return 0;
    }
    View Code
  • 相关阅读:
    Reasoning and Learing学习笔记
    Study in JI During the Summer Vacation
    2018-计算机系机试-A
    2018-计算机系机试(第二批)-E-绝对值排序
    2018-计算机系机试(第二批)-D-最小差值
    2018-计算机系机试(第二批)-C-数字字符个数
    2018-计算机系机试(第二批)-B-二进制输出
    2018-计算机系机试(第二批)-A-最大数
    2018-软工机试-E-热河路(TLE只拿了90分,待思考)
    2015年四川省赛
  • 原文地址:https://www.cnblogs.com/jianrenfang/p/5728316.html
Copyright © 2011-2022 走看看