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;
}
}
}
}