最小生成树算法 大鱼海棠
问题 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小的在前(优先队列不懂的话可以看我博客中优先队列之一类里的题,我已分类好了),一个个取出,如果取出的两个点已经连通,就取下一个,否则“并”(让一个点的根成为另一个点的子根)。