时间复杂度mlogm 先给每条边按边长排序,然后每次都选取最小的边,用并查集判断他们是否联通,若不连通则相连 (否则连接后成环) ,连成n-1条边后退出算法 适用于稀疏图,prim适用于稠密图
模板
#include<cstdio>//kurskal算法 时间复杂度mlogm 先给每条边按边长排序,然后每次都选取最小的边,用并查集判断他们是否联通,若不连通则相连 (否则连接后成环)
#include<algorithm>//适用于稀疏图,prim适用于稠密图
using namespace std;
const int M=1e6+10,N=1e6+10;
struct node{
int x,y,l;//x表示起点,y表示终点,l表示边长
}edge[M];
int fa[N],n,m;//并查集 节点数 边数
inline int find(int x){
return fa[x]==x ? x : fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
fa[find(x)]=find(y);
}
bool cmp(node a,node b){
return a.l<b.l;
}
int kurskal(){
sort(edge,edge+m,cmp);
int cnt=0;//记录已连接的边
int sum=0;//记录权值
for(int i=0;i<m;i++){
int fx=find(edge[i].x);
int fy=find(edge[i].y);
if(fx!=fy){
merge(fx,fy);
sum+=edge[i].l;
if(cnt>=n-1) break;
}
}
return sum;
}
int main(){
return 0;
}
例题
http://poj.org/problem?id=1751
这题用prim算法就不能用链式前向星,因为边太多了,爆内存
而且这题最坑的是给出的已联通的边有很多废边,卡你时间
#include<cstdio>//kurskal算法 时间复杂度mlogm 先给每条边按边长排序,然后每次都选取最小的边,用并查集判断他们是否联通,若不连通则相连 (否则连接后成环)
#include<algorithm>//适用于稀疏图,prim适用于稠密图
using namespace std;
const int M=3e5+500,N=1e3+10;
struct node{
int x,y,l;//x表示起点,y表示终点,l表示边长的平方
}edge[M];
int fa[N],n,m,cnt;//并查集 节点数 边数 edge下标
struct Dot{
int x,y;
}dot[N];
inline void init(){//初始化并查集
for(int i=1;i<=n;i++){
fa[i]=i;
}
}
inline int read(){
int s=0,w=1;char c=getchar();while(c<'0' || c>'9'){
if(c=='-') w*=-1; c=getchar();
}while(c>='0' && c<='9'){
s=(s<<3)+(s<<1)+c-'0';c=getchar();
}return s*w;
}
inline int find(int x){
return fa[x]==x ? x : fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
fa[find(x)]=find(y);
}
bool cmp(node a,node b){
return a.l<b.l;
}
int cal(int x1,int y1,int x2,int y2){
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
void kurskal(){
int cnt_=0;//记录已连接的边 第二易错点 陷阱:不要让cnt_=m,题目中给的已连接的边不一定全部都是最小生成树上的边!
for(int i=0;i<cnt;i++){
int fx=find(edge[i].x);
int fy=find(edge[i].y);
if(fx!=fy){
merge(fx,fy);
printf("%d %d\n",edge[i].x,edge[i].y);
if(cnt_++>=n-1) break;
}
}
}
int main(){
n=read();
init();//这个函数与n有关,请务必放在输入n后!!!
for(int i=1;i<=n;i++){
dot[i].x=read(),dot[i].y=read();
}
m=read();
for(int i=1;i<=m;i++){
int a=read(),b=read();
merge(a,b);
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(find(i)!=find(j))//最大易错点:他俩不连通的时候再建边,不要上来就建边,否则会TEL!这说明给的数据中m条边有大量废边卡时间,一定要把他们剪掉!!!
edge[cnt].x=i,edge[cnt].y=j,edge[cnt++].l=cal(dot[i].x,dot[i].y,dot[j].x,dot[j].y);//剪枝建边
sort(edge,edge+cnt,cmp);//易错:sort是左闭右开!!!所以不要写cnt-1
kurskal();
return 0;
}