定义:如果一个无向连通图不包含回路,那么就是一个树,
比如几个城市的交通路线连通图,而最小生成树就相当于是线路网中选择一条最优解(最短路)
方法1:prim
用到了贪心的思想,对于一个点我们找于之最近(权值最小)的点来建立通路,以此类推下去。
题目
P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
代码实现:
#include<bits/stdc++.h>
using namespace std;
const long long maxx=0x3f3f3f3f3f3f3f3f;
const long long minn=0xc0c0c0c0c0c0c0c0;
const double pi = 4.0*atan(1.0);
#define int long long
#define f(i,n,m) for(long long i=n;i<=m;++i)
#define unf(i,n,m) for(long long i=n;i>=m;--i)
#define kong NULL
#define debug cout<<"sss"<<endl;
struct ww{
int next;int to;int w;
}p[400010];//p是链式前向星的链子,注意要开大一点,毕竟要存路径 而不是存点。
int head[5005],ds[5005],cnt,n,m,tot,now=1,ans;
int add(int a,int b,int c){//前向星加入
p[++cnt].to=b;
p[cnt].w=c;
p[cnt].next=head[a];
head[a]=cnt;
}
bool ff[5005];
void init()
{
cin>>n>>m;
for(int i=1,u,v,w;i<=m;++i)
{
cin>>u>>v>>w;
add(u,v,w),add(v,u,w);
}
}
void solve() {
init();
for(int i=2;i<=n;++i)
{
ds[i]=maxx;
}
for(int i=head[1];i;i=p[i].next){
ds[p[i].to]=min(ds[p[i].to],p[i].w);
}
while(++tot<n){//tot代表边数,最小生成树的边数为n-1
ff[now]=1;
int xiao=maxx;
f(i,1,n){
if(!ff[i]&&xiao>ds[i]){
xiao=ds[i];
now=i;
}
}
ans+=xiao;
for(int j=head[now];j;j=p[j].next){
int v=p[j].to;
if(!ff[v]&&ds[v]>p[j].w)ds[v]=p[j].w;
}//起点为now,所以这里一次遍历,表示所有起点相同的点,即从now可通向的点
}int gg=0;
f(i,1,n){
if(!ff[i]){
gg++;
}
}
if(gg>1)cout<<"orz"<<endl;
else cout<<ans<<endl;
}
signed main( )
{
ios::sync_with_stdio(false);
solve();
return 0;
}
方法2:kruskal算法
先把所有的边按权值大小排序,并认为每一个节点都是孤立的,分属于n个独立的集合,然后按顺序枚举每一条边,把边涉及到的两个点并起来,于是就可得到一个联通树,而后面对于每个遍历到的边权,我们只要判断其是否有必要取(即用并查集判断该边两边的点是否已经联通)。
代码实现(还是上面那题)
#include<bits/stdc++.h>
using namespace std;
const long long maxx=0x3f3f3f3f3f3f3f3f;
const long long minn=0xc0c0c0c0c0c0c0c0;
const double pi = 4.0*atan(1.0);
#define int long long
#define f(i,n,m) for(long long i=n;i<=m;++i)
#define unf(i,n,m) for(long long i=n;i>=m;--i)
#define kong NULL
#define debug cout<<"sss"<<endl;
const int uu=2e5 + 10;
struct ww{
int val;int x;int y;
};
ww pre[uu];
bool panduan(ww x,ww y){
return x.val<y.val;
}
int f[uu];
int find(int x){
if(x==f[x])return x;
return f[x]=find(f[x]);
}
int n,m;
void solve() {
cin>>n>>m;
f(i,1,m){
cin>>pre[i].x>>pre[i].y>>pre[i].val;
}
sort(pre+1,pre+m+1,panduan);
f(i,1,n){
f[i]=i;
}
int fact=0;
f(i,1,m){
if(find(pre[i].x)!=find(pre[i].y)){
fact+=pre[i].val;
f[find(pre[i].y)]=find(pre[i].x);
}
}int gg=0;
f(i,1,n){
if(i==f[i])gg++;
}
if(gg<=1)cout<<fact<<endl;
else cout<<"orz"<<endl;
}
signed main( )
{
ios::sync_with_stdio(false);
solve();
return 0;
}
参考文案:最小生成树浅谈 - 呢没理他 - 博客园 (cnblogs.com);
新手上路,如有不足欢迎讨论。
313
//53523