翻译翻译一份如果i最小生成树问题(prim算法于kruskal算法的应用)

定义:如果一个无向连通图不包含回路,那么就是一个树,

比如几个城市的交通路线连通图,而最小生成树就相当于是线路网中选择一条最优解(最短路)

方法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

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值