【模板】最小生成树

kruskal算法

O ( m l o g m ) O(mlogm) O(mlogm)

#include<bits/stdc++.h>
using namespace std;
const int N=10005;
struct rec{
	int x,y,z;
}e[N];
bool operator <(rec a,rec b) {
	return a.z<b.z;
}

void read(int &x) {
	int f=1;x=0;char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}

int n,m,fa[N];
long long ans;

int find(int x) {
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}
void kruskal() {
    sort(e+1,e+m+1);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++) {
		int x=e[i].x,y=e[i].y,z=e[i].z;
		int u=find(x),v=find(y);
		if(u!=v) {
			fa[x]=y;
		    ans+=e[i].z;
		}
	}
}
int main() {
	read(n),read(m);
	for(int i=1;i<=m;i++) {
		read(e[i].x),read(e[i].y),read(e[i].z);
	}
	kruskal();
	printf("%lld",ans);
}

prim算法

O ( n 2 ) O(n^2) O(n2)

#include<bits/stdc++.h> 
using namespace std;
const int N=105;

void read(int &x) {
	int f=1;x=0;char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}

int n,d[N],a[N][N],ans;
bool v[N];
void prim() {
	memset(d,0x3f,sizeof(d));
	memset(v,0,sizeof(v));
	d[1]=0;
	for(int i=1;i<n;i++) {
		int x=0;
		for(int j=1;j<=n;j++) {
			if(!v[j]&&(x==0||d[j]<d[x])) x=j;
		}
		v[x]=1;
		for(int y=1;y<=n;y++) {
			if(!v[y]) d[y]=min(d[y],a[x][y]);
		}
	}
}
int main() {
	read(n);
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=n;j++) {
			read(a[i][j]);
		}
	}
	prim();
	for(int i=1;i<=n;i++) ans+=d[i];
	printf("%d",ans);
}

eg.北极网络

分析:本题肯定和最小生成树有关,给了k个通信卫星,这k个点是不用与其他点联通的。仿照 k r u s k a l kruskal kruskal算法,依次考虑最短的边,同时记录当前的连通块数量。若 x = y x=y x=y,则跳过;否则,令 t o t − − tot-- tot.若 t o t = k tot=k tot=k,说明剩下的点可以用通信卫星连接,直接输出当前边的长度,就是最小的d值。
证明如下:若连接当前最短的边,对后面的边最多只有一个边无法被选择(因为只占用了一个点),而这个当前最短的边显然是比后面的边更优的。整个思想是贪心。

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=505*505;
struct rec{
	int x,y;
	double z;
}edge[maxn];
bool operator <(rec a,rec b) {
	return a.z<b.z;
}

void read(int &x) {
	int f=1;x=0;char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}

int k,n,m,fa[maxn],xi[maxn],yi[maxn],tot,index;
double f[maxn];

int get(int x) {
	if(fa[x]!=x) fa[x]=get(fa[x]);
	return fa[x];
}
int main() {
	int t=1;
	//read(t);
	while(t--) {
		m=index=0;
	    read(n),read(k);
    	for(int i=1;i<=n;i++) {
    		read(xi[i]),read(yi[i]);
    		for(int j=1;j<i;j++) {
    			edge[++m].z=sqrt(1.0*(xi[i]-xi[j])*(xi[i]-xi[j])+1.0*(yi[i]-yi[j])*(yi[i]-yi[j]));
    			edge[m].x=i;
    			edge[m].y=j;
			}
    	}
    	sort(edge+1,edge+m+1);
	    for(int i=1;i<=n;i++) fa[i]=i;
    	tot=n;
    	if(tot<=k) {
    		printf("0.00\n");
    		continue;
		}
	    for(int i=1;i<=m;i++) {
	    	int x=get(edge[i].x);
	    	int y=get(edge[i].y);
	    	if(x==y) continue;
	    	fa[x]=y;
	    	tot--;
	    	if(tot==k) {
	    		printf("%.2lf\n",edge[i].z);
	    		break;
			}
	    }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值