最小生成树和最小树形图

最小生成树 是在无向图中 是把所有点连接的最小边值;

 

pri 算法:

贪心的思想,每次选择那个入边最短的边。去更新

利用并查集判断2个点是不是已经间接相连了

理解: 相当于 所有人要进入一个场地,如何让所有的人的费用最小。 (人一个一个进去)

s算法

#include <bits/stdc++.h>
using namespace std;
#define ri register int 
#define M 200005 
#define N 5005 

int fa[N];
struct edge{
    int a,b;
    int val;
    bool operator <(const edge &t)const 
    {
        return val<t.val;
    }
}p[M];

int findd(int a)
{
    
    if(fa[a]==a) return a;
    fa[a]=findd(fa[a]); //检查的时候每一步都要好好看,看函数进去的值是什么 是上层的父亲 
    return fa[a];
}

int n,m;
long long ans;
int main(){
    
    scanf("%d%d",&n,&m);
    for(ri i=1;i<=m;i++)
    {
        int a,b,c;
        
        scanf("%d%d%d",&a,&b,&c);
        p[i].val=c;
        p[i].a=a,p[i].b=b;
        
    }
    
    sort(p+1,p+1+m);
    for(ri i=1;i<=n;i++)
    fa[i]=i;
    int trmp=0;
    for(ri i=1;i<=m;i++)
    {
       int l=findd(p[i].a);
       int r=findd(p[i].b);
       if(l==r) continue ;
       
       if(l!=r)
       {
         fa[l]=r;
         ans+=p[i].val;
         trmp++;
       }
    }
    if(trmp==n-1)
    printf("%lld",ans);
    else
    printf("orz");
    return 0;
    
}
View Code

 

不能用prm 算法解决 最小树形图

最小树形图 是有向图的最小生成树

算法 zhuliu

思想: 从入度入手+缩点的+最小边的思想(每一个点弄一个dis【最小边的值】,保存他的前一个);

void zl()
{
    while(1){
    
    for(ri i=1;i<=n;i++) dis[i]=inf;  // 利用了尽量找边最小的思想 
    
    for(ri i=1;i<=m;i++)
    {
        int u,v;
        u=p[i].u,v=p[i].v;
        if(v!=u&&dis[v]>p[i].val){
        pre[v]=u;
        dis[v]=p[i].val;
        }
    }
    for(ri i=1;i<=n;i++)
    {
        if(dis[i]==inf&&i!=root)  // 不存在的情况 
        {
            printf("-1");
            exit(0);    
        }
    }
    int cnt=0;
    for(ri i=1;i<=n;i++) vis[i]=0,id[i]=0;
    
    for(ri i=1;i<=n;i++)
    {
        if(i==root) continue;
        ans+=dis[i];
        
        int v=i;
        while(vis[v]!=i&&!id[v]&&v!=root) /// 找环  
        {
            vis[v]=i;
            v=pre[v];
        }
        if(!id[v]&&v!=root) // 只要不是那2个特殊的情况,代表找到了。 
        {
            id[v]=++cnt;
            for(int u=pre[v];u!=v;u=pre[u])
            {
                id[u]=cnt;
            }
        }
    }
    if(!cnt) 
    {
        printf("%d",ans);
        exit(0);
    }
    for(ri i=1;i<=n;i++)
    {
        if(!id[i]) id[i]=++cnt;
    }
    for(ri i=1;i<=m;i++)
    {
        int v=p[i].v, u=p[i].u;  //////// 新编号 
        p[i].v=id[v];
        p[i].u=id[u];
        if(id[u]!=id[v])
        {
            p[i].val-=dis[v];
        }
    }
    n=cnt;
    root = id[root];
}
}
View Code

 

posted @ 2021-11-09 19:32  VxiaohuanV  阅读(71)  评论(0编辑  收藏  举报