图论-最小生成树

Prim算法

洛谷p3366最小生成树模版题

Prim算法基于点,在无向图中每次选择离已生成的树最近的一个未加入点加入树,随后更新未加入的点的距离。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=5010,MAXM=400010;
struct line
{
    int y,next,w;
}l[MAXM];
int f[MAXN]={0},n,m,num=0;
int flag[MAXN]={0},sum=0,dis[MAXN];
inline void init()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int a,b,v;
        scanf("%d%d%d",&a,&b,&v);
        l[++num].y=b;
        l[num].w=v;
        l[num].next=f[a];
        f[a]=num;
        l[++num].y=a;
        l[num].w=v;
        l[num].next=f[b];
        f[b]=num;
    }
    return;
}

inline void prim()
{
    memset(dis,10,sizeof(dis));
    dis[1]=0;
    for(int i=1;i<=n;i++)
    {
        int mi=1000000,k=0;
        for(int j=1;j<=n;j++)
        if(flag[j]==0&&dis[j]<mi)//寻找最近的未加入点
        {
            mi=dis[j];
            k=j;
        }
        if(k==0)//没有找到,说明图不连通
        {
            printf("orz");
            exit(0);
        }
        flag[k]=1;
        sum+=dis[k];//累加权值
        for(int j=f[k];j;j=l[j].next)
        if(l[j].w<dis[l[j].y])
        dis[l[j].y]=l[j].w;//更新距离
    }
    printf("%d",sum);
    return;
}

int main()
{
    init();
    prim();
    return 0;
}
Kruskal算法

洛谷p1547失去的干草(误

Kruskal算法基于边与并查集的操作,从权值小到大搜索边,如果边连接的两点不属于同一集合就合并。

理解了并查集后,这个还是非常简单的。

#include<bits/stdc++.h>
using namespace std;
struct line
{
	int x,y;
	int w;
}l[10010];
int n,m,fa[2010],ans;
inline int read()
{
	int num=0;
	char c=getchar();
	for(;c<'0'||c>'9';c=getchar());
	for(;c>='0'&&c<='9';c=getchar())num=num*10+c-'0';
	return num;
}

inline bool mycmp(line a,line b)
{
	return(a.w<b.w);
}

inline int getfather(int x)//找父亲顺便压缩路径
{
    if(fa[x]==x)return x;
    fa[x]=getfather(fa[x]);
    return fa[x];
}

void init()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		l[i].x=read();
		l[i].y=read();
		l[i].w=read();
	}
	sort(l+1,l+m+1,mycmp);//排序
	return;
}

void work()
{
	int flag=0;
	for(int i=1;i<=m;i++)
	{
		int tx=getfather(l[i].x);
		int ty=getfather(l[i].y);
		if(tx!=ty)
		{
		    fa[tx]=ty;
		    flag++;
		    ans=l[i].w;//更新当前最长边
		    if(flag==n-1)return;//如果加入的边达到要求
		}
	}
	return;
}

int main()
{
    init();
    work();
    printf("%d",ans);
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值