洛谷P1195 口袋的天空(最小生成树)
题目背景
小杉坐在教室里,透过口袋一样的窗户看口袋一样的天空。
有很多云飘在那里,看起来很漂亮,小杉想摘下那样美的几朵云,做成棉花糖。
题目描述
给你云朵的个数NNN,再给你MMM个关系,表示哪些云朵可以连在一起。
现在小杉要把所有云朵连成KKK个棉花糖,一个棉花糖最少要用掉一朵云,小杉想知道他怎么连,花费的代价最小。
输入格式
每组测试数据的
第一行有三个数N,M,K(1≤N≤1000,1≤M≤10000,1≤K≤10)N,M,K(1 \le N \le 1000,1 \le M \le 10000,1 \le K \le 10)N,M,K(1≤N≤1000,1≤M≤10000,1≤K≤10)
接下来MMM行每行三个数X,Y,LX,Y,LX,Y,L,表示XXX云和YYY云可以通过LLL的代价连在一起。(1≤X,Y≤N,0≤L<10000)(1 \le X,Y \le N,0 \le L<10000)(1≤X,Y≤N,0≤L<10000)
30%30\%30%的数据N≤100,M≤1000N \le 100,M \le 1000N≤100,M≤1000
输出格式
对每组数据输出一行,仅有一个整数,表示最小的代价。
如果怎么连都连不出KKK个棉花糖,请输出'No Answer'。
输入输出样例
输入 #1
3 1 2 1 2 1
输出 #1
1
题目的意思就是将一个图划分成k个连通块,问怎样连边可以使得总边权最小。
先求最小生成树,这样能保证所有节点连起来,这时把n个点划分成k个连通块只需要断掉k-1条边,贪心地选择最大的k-1条边断掉即可。
#include <bits/stdc++.h> using namespace std; int fa[1005]; int n,m,k; struct edge { int x,y,z; }e[10005]; bool cmp(edge a,edge b) { return a.z<b.z; } int get(int x) { if(x==fa[x])return x; return fa[x]=get(fa[x]); } int main() { int i,ans=0,cnt=0; scanf("%d%d%d",&n,&m,&k); for(i=1;i<=n;i++)fa[i]=i; for(i=1;i<=m;i++) { int x,y,l; scanf("%d%d%d",&x,&y,&l); e[i].x=x,e[i].y=y,e[i].z=l; } sort(e+1,e+m+1,cmp); for(i=1;i<=m;i++) { int x=get(e[i].x),y=get(e[i].y); if(x==y)continue; fa[x]=y; cnt++; if(cnt<=n-k)//最小生成树有n-1条边 { ans+=e[i].z; } } cout<<ans<<endl; return 0; }