算法导论机考复习(图相关问题)

文章介绍了两种用于寻找无向图最小生成树的算法,Kruskal算法通过排序边并利用并查集避免环路,而Prim算法则维护一个距离数组,逐步添加与当前集合距离最小的节点。这两种算法都需要保证图的连通性。
摘要由CSDN通过智能技术生成

最小生成树

kruskal算法求最小生成树,把所有的边进行排序,然后依次加入n-1条边,中间要判断是否有环路

用到并查集f,初始化的时候每个点的f都是自己,只要遍历到一条边,就判断两个点是否有共同的f,也就是两个点是否是连通的。

不是就加入到最小生成树中,并且把这两个其中一个的父亲结点更新为另一个点的父亲结点。

//***最小生成树算法***
//Kruskal算法
//图必须是无向图
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int n,m,qi,zh,ans,cnt;
int f[N];
struct node
{
    int x,y,d;
}G[N];
bool cmp(node a,node b)
{
    return a.d<b.d;
}
int findf(int i)
{
    return i=f[i]?i:findf(f[i]);
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
       cin>>G[i].x>>G[i].y>>G[i].d;
    }
    sort(G+1,G+m+1,cmp);
    //每一个点都是一个独立的连通分量
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
    }
    //只需要n-1条边,此时所有的边已经排序好
    for(int i=1;i<=m;i++)
    {
        //考察方法就是考察边的两个结点
        int f1=findf(G[i].x);
        int f2=findf(G[i].y);
        if(f1!=f2)
        {
            ans+=G[i].d;
            f[f1]=f2;
            cnt++;
            if(cnt==n-1)
                break;
        }

    }

    cout<<ans<<endl;
}
/*
5 7
1 2 4
1 4 2
2 4 1
2 3 4
4 3 1
4 5 7
3 5 3
*/

Prim算法求最小生成树算法

维护一个dis数组,初始化为无穷,初始化先把1加进去,然后进行n-1次循环把其他最小的结点依次加进去,如果在循环中间出现了找不到一个最小点,也就是都是INF,说明无法生成最小生成树,根本就不连通。

//***最小生成树算法***
//prim算法
//图必须是无向图
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
const int INF=0x3f3f3f3f;
int n,m,qi,zh,ans,cnt,quan;
int G[N][N];
int dis[N];//图到某个点的距离
bool book[N];//是否加入到图中

//每次都用新加入的边去更新所有点到s的距离
int prim()
{
    //初始化先把1加进去
    dis[1]=0;
    book[1]=1;
    for(int i=1;i<=n;i++)
    {
        dis[i]=min(dis[i],G[1][i]);
    }
    //之后加n-1个距离s最小的结点
    //而且每次加都更新所有邻接结点
    for(int i=2;i<=n;i++)
    {
        int u;
        int minn=INF;
        int t=-1;
        for(int i=1;i<=n;i++)
        {
            if(dis[i]<minn&&!book[i])
            {
                t=1;
                u=i;
                minn=dis[i];
            }
        }
        if(t==-1)//在循环里面就没有找到合适的结点加入
            return -1;
        book[u]=1;
        ans+=dis[u];

        for(int i=1;i<=n;i++)
        {
            dis[i]=min(dis[i],G[u][i]);
        }
    }
    return ans;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            G[i][j]=INF;
        }
        dis[i]=INF;
    }
    for(int i=1;i<=m;i++)
    {
        cin>>qi>>zh>>quan;
        G[qi][zh]=quan;
        G[zh][qi]=quan;
    }
    cout<<prim();

}
/*
5 7
1 2 4
1 4 2
2 4 1
2 3 4
4 3 1
4 5 7
3 5 3
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值