zoukankan      html  css  js  c++  java
  • 最小生成树算法 大鱼海棠

    问题 G: 大鱼海棠

    时间限制: 1 Sec  内存限制: 128 MB
    提交: 29  解决: 12
    [提交][状态][讨论版]

    题目描述

    近期热映的电影《大鱼海棠》灵感来源于《庄子·逍遥游》,讲述了一个掌管海棠花的少女与人类男孩“鲲”的灵魂的奇幻故事。
    所有人类的灵魂都是海里一条巨大的鱼,出生的时候从海的此岸出发,在路途中,有时相遇,有时分开,死的时候去到海的彼岸,之后变成一条沉睡的小鱼,等待多年后的再次出发,这个旅程永远不会结束,生命往复不息。十六岁生日那天,居住在“神之围楼”里的一个名叫椿的女孩变作一条海豚到人间巡礼,被大海中的一张网困住,一个人类男孩因为救她而落入深海死去。为了报恩,为了让人类男孩复活,她需要在自己的世界里,历经种种困难与阻碍,帮助死后男孩的灵魂——一条拇指那么大的小鱼,成长为一条比鲸更巨大的鱼并回归大海。
    然后……我去看了这部电影……电影中主要人物有三个——椿,鲲,湫。在椿生活的世界里,鲲是一条鱼。
    这个世界中有n个城市。编号1至n。椿,鲲,湫居住在城市1。
    鲲在这个世界里行走,是需要通过“水道”的!而在椿的世界里,平时并不会出现“水道”。
    某一天,鲲长大了,即将回到人类世界!椿想和鲲最后一次一起在自己的世界里游历所有的城市。因此,椿向湫寻求帮助,湫施展了魔法,变出了m条水道供椿选择:每条水道连接了两个城市u,v,以及椿建造这条水道需要消耗的法力值w。
    椿可以选择其中的n-1条水道进行建造,但要保证能游历所有的城市,请问椿最少需要消耗多少法力值?
    如果椿无论怎么建造水道都无法保证和鲲游历完所有的城市,请输出-1。

    输入

    多组测试数据。

    每组测试数据,第一行输入n,m。

    n表示有n个城市,m表示椿可以在这m条水道中进行选择。(数据中 n最大为100,m最大为10000)

    接下来m行,每行输入三个数u,v,w。表示可以在城市u和城市v之间建立一条水道,建造该便水道消耗的法力值为w。(w最大为200.)

    数据中,两个城市之间可能多条有费用不一样的水道可供选择。

    输出

    如果无论椿怎么建造水道都不能和鲲游历完所有的城市,请输出-1。

    否则,请输出椿建造水道的需要消耗的最少法力值。

    样例输入

    2 1
    1 2 3
    3 1
    1 2 3
    

    样例输出

    3
    -1


    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <cstring>
    #include <queue>
    using namespace std;
    int pre[105];
    struct node
    {
        int u,v,w;
        friend bool operator< (node a,node b)
        {
            return a.w>b.w;
        }
    };
    int find(int x)//查找他们的根
    {
        int r=x;
        while(pre[r]!=r) r=pre[r];//找根的根,直到找到原根
        return r;
    }
    int main()
    {
        priority_queue<node>q;//用优先队列,使每次取出的w总是最小的
        int n,m;
        node a[10005];
        while(cin>>n>>m)
        {
            while(!q.empty()) q.pop();
            int i;
            for(i=1;i<=m;i++)
            {
                cin>>a[i].u>>a[i].v>>a[i].w;
                pre[i]=i;//用于存放各个点的跟
                q.push(a[i]);
            }
            int k=0;
            int s=0;//存费用(权)
            for(i=1;i<=n-1;i++)//n个点至少需要n-1条边来连通
            {
                while(!q.empty())
                {
                    node x;
                    x=q.top();q.pop();
                    int yv=find(x.v);
                    int yu=find(x.u);
                    if(yv==yu) continue;//如果两个点本来就连通,跳过
                    pre[yu]=yv;//让一个点的根成为另一个点的子根
                    s=s+x.w;
                    k++;//记录已连接的边数
                }
            }
            if(k!=n-1) cout<<-1<<endl;//小于n-1代表没有连通
            else cout<<s<<endl;
        }
        return 0;
    }
                    

        并查集实际上还可以压缩,这个以后再说,我还没学。

      主要的思路就是,把u,v,w存入优先队列,优先队列中w小的在前(优先队列不懂的话可以看我博客中优先队列之一类里的题,我已分类好了),一个个取出,如果取出的两个点已经连通,就取下一个,否则“并”(让一个点的根成为另一个点的子根)。



  • 相关阅读:
    Mysql:Group Replication & Replication
    使用winsw包装服务将nginx包装为Windows服务
    Nginx的一些常用配置
    在ASP.NET Core 2.0中使用Facebook进行身份验证
    展现层实现增删改查
    ABP创建应用服务
    ABP领域层定义仓储并实现
    ABP领域层创建实体
    通过模板创建一个ABP项目
    Android UI组件:布局管理器
  • 原文地址:https://www.cnblogs.com/caiyishuai/p/8330033.html
Copyright © 2011-2022 走看看