最小生成树 prime算法 与克鲁斯卡尔算法

prime算法

用到了贪心的想法,离当前点最近距离的边一定在最小生成树里。

#include<bits/stdc++.h>
using namespace std;
#define maxn 5005
#define inf 1e9
typedef long long ll;
int n,m,mat[maxn][maxn],vis[maxn]; //mat存图,vis表示到当前点的最短距离
bool flag[maxn]; // 用来判断点是否已经在最小生成树中
ll slove()
{
    int ans = 0;
    flag[1] = 1;
    for(int i = 1; i <= n; i++)  //先将点1放入树中
    {
        vis[i] = mat[1][i];
    }

    for(int i = 1; i < n; i++)    
    {

        int mi = inf,next;
        for(int j = 1; j <= n; j++)  //寻找到最小生成树中点距离最近的点
        {
            if(flag[j]==0 && vis[j]<mi)
            {
                next = j;
                mi = vis[j];
            }
        }
        flag[next] = 1; //标记
        ans += mi;
        if(mi == inf)
        {
            cout << "orz" << endl;
            return 0;
        }
        for(int j = 1; j <= n; j++)  // 重置vis数组( vis里存的是已有的点到第j个点的最近距离)
        {
            if(flag[j] == 0 && mat[next][j] < vis[j])
                vis[j] = mat[next][j];
        }

    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);

    cin >> n >> m;

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            mat[i][j] = inf;

    for(int i = 1; i <= m; i++)
    {
        int x,y,z;
        cin >> x >> y >> z;
        if(mat[x][y] > z)
            mat[x][y] = mat[y][x] = z; // 基本操作
    }
    cout << slove() << endl;
    return 0;
}

克鲁斯卡尔算法

以边为重点,按小排序后选边,用并查集来确保不会出现成环的情况

#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
#define maxn 200005
#define mod 1e9+7
#define inf 1e18
typedef long long ll;
struct Why
{
    ll a,b,c;
}arr[maxn];
ll n,m,r[maxn],ans,num;
bool cmp(Why a,Why b)
{
    return a.c < b.c;
}
ll fi(ll x)
{
    return r[x] == x? x: r[x] = fi( r[x] );
}
ll slove()
{
        for(ll i = 1; i <= m; i++)
        {
            if( fi(arr[i].a) != fi(arr[i].b)  )
            {
                 r[ fi( arr[i].b  ) ] =  arr[i].a ;
                 ans += arr[i].c;
                 num++;
            }
            if(num == n-1)
                break;
        }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);

    cin >> n >> m;

    for(ll i = 1; i <= m; i++)
        cin >> arr[i].a >> arr[i].b >> arr[i].c;

    sort(arr+1,arr+1+m,cmp);

    for(ll i = 1; i <= n; i++)
        r[i] = i;

    cout << slove() << endl;

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值