题意:有n个等级,某些等级是相连的,但需要费用w才可以解锁访问,解锁之后再次访问该等级不需要任何花费,从等级1开始,访问n个等级花费的最小值,另外一个条件是可以让某两个等级之间的花费变为0。
思路:先用最小生成树求一下最小边权之和与最小生成树中的最大边权值maxx,再用类似最小生成树的方法求一下,在不成环的前提下,如果边权值>=maxx的边并且加上这条边能构成最小生成树,那么tot++(tot最小生成树的个数);否则就让u的父节点归结于v的父节点。继续遍历。
注意要是用long long,代码中将long long用int代替了。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define int long long
#define lowbit(x) ((~x+1)&x)
using namespace std;
const int N = 5e5+10;
struct node {
int u,v,w;
}a[N];
int cnt,f[N],val[N];
int n,m,k;
int ans,maxx;
int u,v,w;
bool cmp(node a,node b) {
return a.w<b.w;
}
int Find(int x) {
if(x!=f[x]) {
f[x] = Find(f[x]);
}
return f[x];
}
void join(int u,int v,int w) {
int x = Find(u);
int y = Find(v);
if(x!=y) {
f[x] = y;
maxx = w;
k++;
ans+=w;
}
}
signed main() {
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1; i<=n; i++) f[i] = i;
for(int i=1; i<=m; i++) {
cin>>u>>v>>w;
a[i].u = u;
a[i].v = v;
a[i].w = w;
}
sort(a+1,a+m+1,cmp);
int i=1;
while(k<n-1) {
join(a[i].u,a[i].v,a[i].w);
i++;
}
for(int i=1; i<=n; i++) f[i] = i;
int tot=0;
for(int i=1; i<=m; i++) {
if(Find(a[i].u)!=Find(a[i].v)) {
if(a[i].w>=maxx) {
tot++;
}
else {
f[Find(a[i].u)] = Find(a[i].v);
}
}
}
cout<<ans-maxx<<' '<<tot<<endl;
return 0;
}
代码参考于https://blog.csdn.net/luoxutimberjack/article/details/104303560