自学内容网 自学内容网

代码随想录第五十七天

prim算法

1.算法基本概念

最小生成树 (Minimum Spanning Tree, MST)

  • 是图中的一个子图,包含所有顶点
  • 构成一棵树(无环连通图)
  • 所有边的权重和最小

Prim 算法核心思想

  • 从单个顶点开始生长
  • 采用贪心策略,每次选择最优的当前选择
  • 通过切分定理保证正确性

prim三部曲:

  1. 第一步,选距离生成树最近节点
  2. 第二步,最近节点加入生成树
  3. 第三步,更新非生成树节点到生成树的距离(即更新minDist数组)

minDist数组 用来记录 每一个节点距离最小生成树的最近距离

2.例题 53.寻宝

题目描述

在世界的某个区域,有一些分散的神秘岛屿,每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路,方便运输。

不同岛屿之间,路途距离不同,国王希望你可以规划建公路的方案,如何可以以最短的总公路距离将 所有岛屿联通起来(注意:这是一个无向图)。

给定一张地图,其中包括了所有的岛屿,以及它们之间的距离。以最小化公路建设长度,确保可以链接到所有岛屿。

输入描述

第一行包含两个整数V 和 E,V代表顶点数,E代表边数 。顶点编号是从1到V。例如:V=2,一个有两个顶点,分别是1和2。

接下来共有 E 行,每行三个整数 v1,v2 和 val,v1 和 v2 为边的起点和终点,val代表边的权值。

输出描述

输出联通所有岛屿的最小路径总距离

输入示例

7 11
1 2 1
1 3 1
1 5 2
2 6 1
2 4 2
2 3 2
3 4 1
4 5 1
5 6 2
5 7 1
6 7 1

输出示例

6

提示信息

数据范围:
2 <= V <= 10000;
1 <= E <= 100000;
0 <= val <= 10000;

如下图,可见将所有的顶点都访问一遍,总距离最低是6.

img

思路:

这道题要求我们求出以最小化公路建设长度,确保可以链接到所有岛屿的值,我们可以用prim算法来对其进行解答。我们需要设一个数组专门来存储最小权重,其次我们需要找出局部最优的值,并且每找出一个点我们需要更新最短距离,然后继续寻找下面的节点,最后找出答案就行了。

解答:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
int main()
{
    int V,E;
    int x,y,k;
    scanf("%d %d",&V,&E);
    int** graph = malloc(sizeof(int*)*(V+1));
    for(int i = 0;i <= V;i++)
    {
        graph[i] = malloc(sizeof(int)*(V+1));
    }
    for(int i = 0;i <= V;i++)
    {
        for(int j = 0;j <= V;j++)
        {
            graph[i][j] = 10001;
        }
    }
    while(E--)
    {
        scanf("%d %d %d",&x,&y,&k);
        graph[x][y] = k;
        graph[y][x] = k;
    }
    int* minilist = malloc(sizeof(int)*(V+1));
    for(int i = 0;i <= V;i++)
    {
        minilist[i] = 10001;
    }
    bool* istree = malloc(sizeof(bool)*(V+1));
    for(int i = 0;i <= V;i++)
    {
        istree[i] = false;
    }
    for(int i = 1;i <= V;i++)
    {
        int cur = -1;
        int minvalue = INT_MAX;
        for(int j = 1;j <= V;j++)
        {
            if(!istree[j] && minvalue > minilist[j])
            {
                minvalue = minilist[j];
                cur = j;
            }
        }
        istree[cur] = true;
        for(int j = 1;j <= V;j++)
        {
            if(!istree[j] && minilist[j] > graph[cur][j])
            {
                minilist[j] = graph[cur][j];
            }
        }
    }
    int result = 0;
    for(int i = 2;i <= V;i++)
    {
        result += minilist[i];
    }
    printf("%d",result);
}

kruskal算法

  1. Kruskal 算法的核心思想:

    按照边的权重从小到大的顺序,选择不会形成环的边来构建最小生成树。

  2. 算法步骤:

  • 将图中所有边按权重从小到大排序
  • 初始时,每个顶点都是一个单独的连通分量
  • 依次考察每条边,如果这条边连接的两个顶点不在同一个连通分量中,就选择这条边
  • 使用并查集来判断和合并连通分量
  • 重复这个过程直到选择了n-1条边(n 是顶点数)

prim 算法是维护节点的集合,而 Kruskal 是维护边的集合

53.寻宝

题目描述

在世界的某个区域,有一些分散的神秘岛屿,每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路,方便运输。

不同岛屿之间,路途距离不同,国王希望你可以规划建公路的方案,如何可以以最短的总公路距离将 所有岛屿联通起来(注意:这是一个无向图)。

给定一张地图,其中包括了所有的岛屿,以及它们之间的距离。以最小化公路建设长度,确保可以链接到所有岛屿。

输入描述

第一行包含两个整数V 和 E,V代表顶点数,E代表边数 。顶点编号是从1到V。例如:V=2,一个有两个顶点,分别是1和2。

接下来共有 E 行,每行三个整数 v1,v2 和 val,v1 和 v2 为边的起点和终点,val代表边的权值。

输出描述

输出联通所有岛屿的最小路径总距离

输入示例

7 11
1 2 1
1 3 1
1 5 2
2 6 1
2 4 2
2 3 2
3 4 1
4 5 1
5 6 2
5 7 1
6 7 1

输出示例

6

提示信息

数据范围:
2 <= V <= 10000;
1 <= E <= 100000;
0 <= val <= 10000;

如下图,可见将所有的顶点都访问一遍,总距离最低是6.

img

思路:

为了解决这道题,我们首先将所有边按权重从小到大排序,然后从最小权重的边开始选择。每次选择一条边时,通过并查集判断这条边的两个顶点是否已经连通(在同一个集合中)。如果不连通,就将这条边加入最小生成树,并在并查集中合并这两个顶点所在的集合;如果已经连通,说明加入这条边会形成环,就跳过这条边。当选择的边数达到顶点数减一时,算法结束,此时所有选中边的权重之和就是最小生成树的总权重。这个过程中,并查集主要用于快速判断顶点是否连通和合并顶点所在的集合。

解答:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
struct Edges
{
    int l,r,value;
};
int compare(const void* a,const void* b)
{
   return ((struct Edges*)a)->value - ((struct Edges*)b)->value;
}
int N = 10001;
int* father;
void init()
{
    father = malloc(sizeof(int)*N);
    for(int i = 0;i < N;i++)
    {
        father[i] = i;
    }
}
int find(int x)
{
    if(father[x] != x)father[x] = find(father[x]);
    return father[x];
}
void unite(int x,int y)
{
    x = find(x);
    y = find(y);
    if(x == y)return;
    father[y] = x;
}
int main()
{
    int V,E;
    int result_val = 0;
    scanf("%d %d",&V,&E);
    struct Edges* edges = malloc(sizeof(struct Edges)*E);
    for(int i = 0; i < E;i++)
    {
        scanf("%d %d %d",&edges[i].l,&edges[i].r,&edges[i].value);
    }
    qsort(edges,E,sizeof(struct Edges),compare);
    init();
    int count = 0;
    for(int i = 0;i < E;i++)
    {
        int x = find(edges[i].l);
        int y = find(edges[i].r);
        if(x != y)
        {
            result_val += edges[i].value;
            unite(x,y);
            count++;
            if(count == V-1)
            {
                break;
            }
        }
    }
    printf("%d",result_val);
}

原文地址:https://blog.csdn.net/2301_80630236/article/details/144406622

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!