标签:NC53074 const int kruskal 独一无二 Forsaken long edges 边权
一、题目
二、思路
题目大意就是一棵最小生成树可能有多种不同的组成方式,我们要去掉哪些边才能使整个图只有一种最小生成树,并对去掉的这些边求和
首先一棵树如果有多种不同的组成方式,在kruskal的方法下,只有可能是在选边的时候出现了多条相同边权的边连接着两个已经连接上的子树
所以直接对kruskal进行修改即可,在选边时遍历相同边权的边,先将未连接的边的权值全加起来,再进行连边,因为连上的边不是重复的边,所以我们的答案应该再减去连上的边的权值
三、代码
#include<bits/stdc++.h>
using namespace std;
const int N = 400020;
int n, m;
int s[N];
long long ans = 0; //注意开long long,不然可能爆int
struct Edge{
int u, v;
int w;
bool operator < (const Edge & b) const{
return w < b.w;
}
}edges[N];
void init(){
for(int i = 0; i <= n; i ++) s[i] = i;
}
int find(int x){
if(s[x] != x) return s[x] = find(s[x]);
return x;
}
void kruskal(){
sort(edges + 1, edges + 1 + m);
int j = 1;
for(int i = 1; i <= m; i){ //这里直接用while更好,i注意不会自增
while(edges[i].w == edges[j].w && j <= m) j ++; //j一直自增到下一个不同边权的位置
for(int z = i; z < j; z ++){
int u = edges[z].u;
int v = edges[z].v;
if(find(u) != find(v)){
ans += edges[z].w;
}
}
for(int z = i; z < j; z ++){
int u = edges[z].u;
int v = edges[z].v;
if(find(u) != find(v)){
ans -= edges[z].w;
s[find(u)] = find(v);
}
}
i = j; //因为前j条边已经遍历完了,所以i直接到j的位置即可
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++){
cin >> edges[i].u >> edges[i].v >> edges[i].w;
}
init();
kruskal();
cout << ans << endl;
}
标签:NC53074,const,int,kruskal,独一无二,Forsaken,long,edges,边权 来源: https://www.cnblogs.com/ZIENxc/p/15120187.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。