最小生成树

1.最小生成树:是指在一个加权连通图中,找到一颗生成树(生成树是图的一个子图,它包含了图中所有顶点,但是没有成环),使得树上所有边的权值之和最小。所以有n个顶点,n-1条边

2.两种算法

         2.1 prim(普利姆算法) :将所有的点分成两个区域,区域1已选择的,区域2未选中状态,每次从区域2中选一个离区域1中任意一点最近的加入。

#include
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 505;
int a[maxn][maxn];
int vis[maxn], dist[maxn];
int n, m;
int u, v, w;
long long sum = 0;
int prim(int pos) {
    dist[pos] = 0;
    //一共有n个点,就需要遍历n次,每次寻找一个权值最小的点,记录其下标
    for (int i = 1; i <= n; i++) {
        int cur = -1;
        for (int j = 1; j <= n; j++) {
            if (!vis[j] && (cur == -1 || dist[j] < dist[cur])) {
                cur = j;
            }
        }
        //剪枝 
        if (dist[cur] > INF)return INF;
        sum += dist[cur];
        vis[cur] = 1;
        //只更新还没有找到最小权值的点
        for (int k = 1; k <= n; k++) {
            if (!vis[k])dist[k] = min(dist[k], a[cur][k]);
        }
    }
    return sum;
}
int main() {
    cin >> n >> m;
    memset(a, 0x3f, sizeof(a));
    memset(dist, 0x3f, sizeof(dist));
    //输入边以及权值
    for (int i = 1; i <= m; i++) {
        cin >> u >> v >> w;
        a[u][v] = w;
        a[v][u] = w;
    }
    int value = prim(1);
    if (value >= INF)puts("impossible");
    else cout << sum;
    return 0;
}

2.2库鲁斯卡尔算法

         库鲁斯卡尔算法是一种巧妙利用并查集来求最小生成树的算法

         库鲁斯卡尔算法首先将所有的边按从小到大的顺序排序,并认为每一个点都是孤立的,然后按顺序枚举每一条边(每次都选择最小的边,而且这条边的两个顶点分属于两个不同的集合),如果这条边连接着两个不同的集合,那么就把这条边加入最小生成树,这两个不同的集合就合并成了一个集合,如果这两条边连接的两个点属于同一集合,就跳过,知道选取了n-1条边

#include
#include
using namespace std;
const int maxn = 2e5 + 10;
struct node {
    int x, y, z;
}edge[maxn];
bool cmp(node a, node b) {
    return a.z < b.z;
}
int fa[maxn];
int n, m, u, v, w;
long long sum;
int get(int x) {
    return x == fa[x] ? x : fa[x] = get(fa[x]);
}
int main() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        cin >> edge[i].x >> edge[i].y >> edge[i].z;
    }
    for (int i = 1; i <= n; i++) {
        fa[i] = i;
    }
    sort(edge + 1, edge + 1 + m, cmp);
    //每次加入最短的边
    for (int i = 1; i <= m; i++) {
        int x = get(edge[i].x);
        int y = get(edge[i].y);
        if (x == y)continue;
        fa[y] = x;
        sum += edge[i].z;
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (i == fa[i])ans++;
    }
    if (ans > 1)puts("impossible");//ans大于1说明图是不连通的
    else cout << sum;
    return 0;
}

你可能感兴趣的:(算法,数据结构)