题目链接: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了
果然是我太弱了吗
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
【总结】
头可断,血可流,代码错不得
注意判断选入边的条件,理解并查集的运用,不能死记硬背