最小生成树及相关基础应用
算法kruskal,这是我春季赛前突击的一个算法,当时我貌似并查集都不怎么会,还是现学的...
先说一下这个基础算法的思路吧,先把所有边按照边权排序,把每棵树当作一棵子树,如果他们在一棵字树内就不管它,因为我们他们之间已经连边了,如果不在一棵子树内,就将他们连
起来
代码如下,码风非常优美,不接受反驳(doge
#include<bits/stdc++.h>
using namespace std;
int fa[100006];
int n,m;
int k;
int s,maxx;
struct node{
int u,v,c;
}a[200005];
int find(int x){
if(x!=fa[x]){
return find(fa[x]);
}
return x;
}
bool cmp(node a,node b){
return a.c<b.c;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
cin>>a[i].u>>a[i].v>>a[i].c;
}
sort(a+1,a+1+m,cmp);
int sum=0;
for(int i=1;i<=m;i++){
int ax=find(a[i].u),ay=find(a[i].v);
if(ax!=ay){
fa[ax]=ay;
k++;
sum+=a[i].c;
}
maxx=max(maxx,a[i].c);
}
if(k<n-1){
cout<<"orz";
}
else{
cout<<sum;
}
return 0;
}
接下来上一道例题吧
刚开始我把这道题当成只有一个发电站了,想跑n此kruskal,但显然这是十分愚蠢的,这道题考虑建一个超级原点,将所有点与其相连,边权即为在该点建发电站的点权,为什么可以这么做
呢,这样的话我们相当于对于将一个地点有两种到达方式,要么直接建发电站,要么就通过连边来实现,初始化后跑一遍Kruskal板子就可以了
代码如下
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,ans,anss;
int fa[1005];
struct node{
int u,v,c,money;
}p[100005];
bool cmp(node a,node b){
return a.c<b.c;
}
int find(int x){
if(x==fa[x]){
return x;
}
else{
return find(fa[x]);
}
}
signed main()
{
anss=1e18;
cin>>n;
for(int i=0;i<=n;i++){
fa[i]=i;
}
int a=1;
for(int i=1;i<=n;i++){
cin>>p[i].money;
p[++a].u=0;
p[a].v=i;
p[a].c=p[i].money;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>p[++a].c;
p[a].u=i;
p[a].v=j;
}
}
sort(p+1,p+1+(n*n+n),cmp);
for(int j=1;j<=(n*n+n);j++){
int ax=find(p[j].u);
int ay=find(p[j].v);
if(ax!=ay){
fa[ax]=ay;
ans+=p[j].c;
k++;
}
}
cout<<ans;
return 0;
}
warning:不能判连几条边,因为不能确定要建多少发电站
最后一道
这是一道思维题(doge,但蒟蒻的码力貌似仍然无法把自己的思路写出来
这道题我是这样想的,怎么样才能使你的最小生成树唯一呢,很明显,只有当其他边都严格大于树上的那条就可以了,于是我们就可以得出结果即两棵子树之间的边数*(最小生成树实际边权-1),两颗子树之间的边数很显然就是两者大小相乘再减去生成树上的那条边,所以在这个过程中需要开数组维护,键值为每棵子树的大小,这样就可以轻松做出此题了
#include<bits/stdc++.h>
//#define int long long
using namespace std;
int n;
const int maxn= 1e5+5;
long long fa[maxn];
long long siz[maxn];
long long find(long long x){
if(x==fa[x]){
return x;
}
else{
return fa[x]=find(fa[x]);
}
}
struct node{
long long u,v,w;
}p[maxn];
bool cmp(node a,node b){
return a.w<b.w;
}
signed main(){
ios::sync_with_stdio(false);
cin>>n;
long long sum=0;
for(int i=1;i<=maxn;i++){
fa[i]=i;
}
for(int i=1;i<=maxn;i++){
siz[i]=1;
}
for(int i=1;i<=n-1;i++){
cin>>p[i].u>>p[i].v>>p[i].w;
}
sort(p+1,p+1+n-1,cmp);
for(int i=1;i<=n-1;i++){
int ax=find(p[i].u);
int bx=find(p[i].v);
if(ax!=bx){
sum+=p[i].w;
fa[ax]=bx;
sum+=(p[i].w+1)*(siz[bx]*siz[ax]-1);
siz[bx]+=siz[ax];
}
}
cout<<sum;
return 0;
}
the end!