[vijos1234]口袋的天空<最小生成树>

题目链接:https://vijos.org/p/1234

白天刚刚写完prim的算法,晚上就心血来潮的打了一道最小生成树的题

虽然有题解说可以用prim做,但是这道题明显是加最小的边,感觉kruskal方便多了

但是愉快的是我竟然不是一次过,最后发现是题意理解问题,我之前读了很多遍题,还是以为n朵云不用用完,但其实是n朵云要用完并成为k个棉花糖

首先可以知道的是,k个棉花糖中有k-1个是单个的云,因为单个的云就是不要花费的,所以生成树就是在剩下的n-k+1朵云中产生,然后这n-k+1朵云最多用n-k+1-1条边连接是最优的,所以其实就是kruskal选出n-k+1-1条边的最小价值

然后就是一个裸的kruskal了,然后由于很久没打kruskal了,我竟然自作聪明的加了vis数组,然后光荣爆零,最后删去vis,只用并查集判断就瞬间a了

果然是我太弱了吗

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #define maxn 10005
 8 using namespace std;
 9 
10 struct edge{
11     int  u,v,w;
12 }e[2*maxn];
13 
14 int n,m,k,pos,tot,ans;
15 int head[maxn],fa[maxn];
16 
17 int read(){
18     int xx=0,ff=1;char ch=getchar();
19     while(ch<'0'||ch>'9'){if(ch=='-')ff=-1;ch=getchar();}
20     while(ch>='0'&&ch<='9'){xx=xx*10+ch-'0';ch=getchar();}
21     return xx*ff;
22 }
23 
24 void adde(int u,int v,int w){
25     e[++pos].u=u;
26     e[pos].v=v;e[pos].w=w;
27 }
28 
29 int comp(const void*a,const void*b){
30     return (*(struct edge*)a).w>(*(struct edge*)b).w?1:-1;
31 }
32  
33 int find_(int x){
34     if(fa[x]==x)return fa[x];
35     return fa[x]=find_(fa[x]);
36 } 
37  
38 int main(){
39     scanf("%d",&n);m=read();k=read();
40     for(int i=1;i<=m;i++){
41         int u,v,w;
42         u=read();v=read();w=read();
43         adde(u,v,w);
44     }    
45     if(k>n){
46         printf("No Answer");return 0;
47     }
48     for(int o=1;o<=n;o++)
49         fa[o]=o;
50     qsort(e,m+1,sizeof(e[0]),comp);
51     for(int i=1;i<=m;i++){
52         int u=e[i].u,v=e[i].v;
53         int fu=find_(u);int fv=find_(v);
54         if(fu!=fv){
55             fa[fu]=fv;
56             tot++;vis[fv]=1;ans+=e[i].w;
57         }
58         if(tot>=n-k+1-1){
59             printf("%d",ans);return 0;
60         }
61     }
62     printf("No Answer");
63 }
kruskal

【总结】

头可断,血可流,代码错不得

注意判断选入边的条件,理解并查集的运用,不能死记硬背

原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7749238.html