最小生成树

例题

https://www.luogu.com.cn/problem/P3366

 

 方法一:prim算法

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
#define maxn 5001
#define inf 0x3f3f3f3f
int n, m;
int edges[maxn][maxn];
int ecost[maxn];

int prim()
{
    int allcount = 0;
    ecost[1] = 0;//不使用vis数组来标记是否访问过,而是使用ecost【】=0表示该节点已经加入到了最小生成树中
    for (int i = 2; i <= n; i++)
    {
        ecost[i] = edges[1][i];
    }

    int mins = inf, mini = -1;
    for (int i = 2; i <= n; i++)
    {
        mins = inf, mini = -1;
        for (int j = 1; j <= n; j++)
        {
            if (ecost[j] != 0 && ecost[j] < mins)
            {
                mins = ecost[j]; mini = j;
            }
        }
        if (mini == -1)return -1;
        allcount += ecost[mini];
        ecost[mini] = 0;
        for (int j= 2; j <= n; j++)
        {
            if (ecost[j]!=0 && edges[mini][j] < ecost[j])
                ecost[j] =edges[mini][j] ;
        }

    }
    return allcount;
}


int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            edges[i][j] = inf;
    for (int i = 0; i < m; i++)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
         if (edges[a][b] != 0)//这里看输入实例发现存在重边(1 2 300 ;1 2 500; 2 1 700  应该取300)
        {
            if(c<edges[a][b])
                edges[a][b] = edges[b][a] = c;
        }
        else edges[a][b] = edges[b][a] = c;
            if (a == b)
            edges[a][b] = edges[b][a] = 0;
    }
    int answer = prim();
    if (answer == -1)printf("orz");
    else printf("%d", answer);

}

注意事项:要在输入的时候提前处理重边的情况  注意edge数组要进行初始化为INF !!!!!

使用链式前向星:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
#define maxn 5001
#define maxm 200005
#define inf 0x3f3f3f3f
int n, m,cnt=0;

int ecost[maxn],head[maxn];
struct edge
{
    int to;
    int dis;
    int next;
}e[maxm*2];

void addedge(int u, int v, int w)
{
    cnt++;
    e[cnt].to = v;
    e[cnt].dis = w;
    e[cnt].next = head[u];
    head[u] = cnt;
}

int prim()
{
    int allcount = 0;
    for (int i = 1; i <= n; i++)
    {
        ecost[i] = inf;
    }
    ecost[1] =0;
    for (int i = head[1]; i; i = e[i].next)
    {
        int y = e[i].to;
        ecost[y] = min(ecost[y],e[i].dis);//这里进行了去除重边的判断
    }

    int mins = inf, mini = -1;
    for (int i = 2; i <= n; i++)
    {
        mins = inf, mini = -1;
        for (int j = 1; j <= n; j++)
        {
            if (ecost[j] != 0 && ecost[j] < mins)
            {
                mins = ecost[j]; mini = j;
            }
        }
        if (mini == -1)return -1;
        allcount += ecost[mini];
        ecost[mini] = 0;
        for (int i = head[mini]; i; i = e[i].next)
        {
            int  y = e[i].to;
            if (ecost[y] != 0 && ecost[y] > e[i].dis)
                ecost[y] = e[i].dis;
        }

    }
    return allcount;
}


int main()
{
    scanf("%d%d", &n, &m);
    
    for (int i = 0; i < m; i++)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        addedge(a, b, c);
        addedge(b, a, c);
    }
    int answer = prim();
    if (answer == -1)printf("orz");
    else printf("%d", answer);

}

法二:kruskal算法

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
#define maxn 5001
#define maxm 200005
#define inf 0x3f3f3f3f
int n, m, cnt = 0,allcount=0;

int ecost[maxn], father[maxn];
struct edge
{
    int to;
    int dis;
    int from;
}e[maxm];
bool cmp(struct edge&a, struct edge &b)
{
    return a.dis < b.dis;
}


int find(int x)
{
    if (x == father[x])return x;
    return father[x] = find(father[x]);
}
int kruskal()
{
    sort(e, e + m, cmp);
    for (int i = 0; i <m; i++)//一共m条边。一条一条判断
    {
        int tempa, tempb;
        tempa = find(e[i].from); tempb = find(e[i].to);
        if (tempa == tempb)continue;
        allcount += e[i].dis;
        father[tempa] = tempb;    
    }

    return allcount;
}



int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i <= n; i++)
        father[i] = i;
    for (int i = 1; i <=m; i++)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        e[cnt].from = a; e[cnt].to = b; e[cnt].dis = c;
        cnt++;
    }
    int answer = kruskal();
    if (answer == -1)printf("orz");
    else printf("%d", answer);

}

 

posted @ 2020-06-21 09:46  Jason66661010  阅读(169)  评论(0编辑  收藏  举报