luoguP1195 口袋的天空
emmmmm
最小生成树,kruskal
大概是dtx教的,%%%
这道题是学长推荐做的(我点名要水题
/*超喜欢题面嗷
漂亮的天空上有漂亮的云彩,漂亮的孩子做着漂亮的梦
无视以上废话,看题
其实和最小生成树的模版题没什么区别(悄咪咪表示某谷测试点里没有输出orz的点
我们只需要想一下要做出k个棉花糖
就是生成k棵树
总共n个点
生成1棵树连边n - 1条
生成2棵树连边n - 2条
.
.
.
生成k棵树连边n - k条
在kruskal函数中加一个计数就好了
然后我在这里再讲一下kruskal吧
(prim没人给我讲,也看不懂【斜眼笑
众所周知(???我可能看学长博客多了?用词突然相似
kruskal和prim是求最小生成树的两种算法
区别嘛。。。应该是,kruskal将边排序,prim更新节点连最小边?
都是贪心的思路
从任意点出发,首先选择最短的边与之相连,再选择与这棵树之间距离最短的边相连,最后输出的一定是最优解(这是两者的总体思路
那么kruskal是将所有边排序,从最小的边开始连接两个点
可能连的两条最短边不在同一处,但连下去,总会将所有点连到一起
但是需要注意如果选的边连出了环,那一定不是最优解,此时连的边就应该舍掉
(orz被学长指出其实是因为不符合树的性质orz【捂脸
这里我们可以用并查集来判断是否会连成环
这样就结束了
emmmm看代码吧
#include<cstdio> #include<algorithm> using namespace std; const int maxn = 10010; int n,m,k,flag = 0; int fa[maxn]; struct edge{ int from,to,weight; }a[maxn];//用结构体记录每条边连接的点和边权 int get(int x){ if(fa[x] == x) return x; else return fa[x] = get(fa[x]); }//并查集 int cmp(edge x,edge y){ return x.weight < y.weight; }//排序的定义(根据边权大小 int kruskal(){ int ans = 0,num = 0; sort(a,a + m,cmp); for(int i = 0;i < m;i++){ int l = get(a[i].from); int r = get(a[i].to); if(l != r){//判断是否成环 fa[l] = r; ans += a[i].weight; num++; if(num == n - k){//计数,判断是否能生成k棵树 flag = 1;//标记一下 break; } } } return ans; } int main(){ scanf("%d%d%d",&n,&m,&k); for(int i = 0;i < n;i++) fa[i] = i; for(int i = 0;i < m;i++) scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].weight); if(flag == 0) printf("%d",kruskal()); else printf("No Answer"); return 0; }