HDU 3371 Connect the Cities(并查集+Kruskal)

题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=3371

思路:

这道题很明显是一道最小生成树的题目,有点意思的是,它事先已经让几个点联通了。正是因为它先联通了几个点,所以为了判断连通性 很容易想到用并查集+kruskal。

不过要注意 这题有一个坑点,就是边数很多 上限是25000,排序的话可能就超时了。而点数则比较少 上限是500,所以很多人选择用Prim做。但我个人觉得这样连通性不好判断。其实边数多没关系,我们只要去重就好啦,用邻接矩阵存下两点间的最小权重 再排序即可,这样就不会超时啦~

 

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 const int inf=1e5;
 7 struct node{
 8     int v,u,w;
 9     bool operator <(const node &x) const{
10         return w<x.w;
11     }
12 };
13 int pre[505];
14 int mp[505][505];
15 int n,m,k;
16 int cnt;
17 vector<node>v;
18 void init(){
19     for(int i=1;i<=n;i++){
20         pre[i]=i;
21         for (int j=1; j<=n; j++) {
22             mp[i][j]=inf;
23         }
24     }
25 }
26 int query(int x){
27     int r=x;
28     while (pre[x]!=x) {
29         x=pre[x];
30     }
31     pre[r]=x;
32     return x;
33 }
34 bool join(int x,int y){
35     int fx=query(x);
36     int fy=query(y);
37     if(fx!=fy){
38         pre[fx]=fy;
39         return true;
40     }
41     return false;
42 }
43 int kruskal(){
44     int res=0;
45     for(int i=0;i<v.size();i++){
46         if(join(v[i].v, v[i].u)){
47             res+=v[i].w;
48         }
49     }
50     return res;
51 }
52 int main(){
53     int t;
54     int res;
55     scanf("%d",&t);
56     while (t--) {
57         cnt=0;
58         v.clear();
59         scanf("%d%d%d",&n,&m,&k);
60         init();
61         for (int i=0; i<m; i++) {
62             int v,u,w;
63             scanf("%d%d%d",&v,&u,&w);
64             mp[v][u]=min(mp[v][u],w);//保留最小权重
65         }
66         for (int i=0; i<k; i++) {
67             int num,a,b;
68             scanf("%d",&num);
69             if(num) scanf("%d",&a);
70             for (int j=1; j<num; j++) {
71                 scanf("%d",&b);
72                 join(a, b);
73             }
74         }
75         for (int i=1; i<=n; i++) {
76             for (int j=1; j<=n; j++) {
77                 if(mp[i][j]==inf || i==j)   continue;
78                 v.push_back({i,j,mp[i][j]});//重新导入边,去掉了重复部分
79             }
80         }
81         sort(v.begin(), v.end());
82         res=kruskal();
83         for (int i=1; i<=n; i++) {
84             if(pre[i]==i)   cnt++;//算连通块个数
85         }
86         if(cnt==1)  printf("%d\n",res);
87         else printf("-1\n");
88     }
89 }

 

转载于:https://www.cnblogs.com/uniles/p/7287076.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值