prim~(够5个了)

#include<iostream>

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define MAXN 1000010
#define INF 10000010

using namespace std;

inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

struct Edge{
	int to;
	int next;
	int w;
}edge[MAXN];

int n;
int m;
int head[MAXN];
int cnt=0;
int dis[MAXN];
int ans;
int visit[MAXN];

inline void add(int u,int v,int w){
	cnt++;
	edge[cnt].to=v;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	head[u]=cnt;
}

bool prim(){
	dis[1]=0;
	for(int i=1;i<=n;i++){
		int u=-1;
		int min=INF;
		for(int j=1;j<=n;j++){
			if(min>dis[j]&&!visit[j]){
				u=j;
				min=dis[j];
			}
		}
		if(u==-1){
			return false;
		}
		visit[u]=true;
		ans+=dis[u];
		for(int j=head[u];j;j=edge[j].next ){
			int t=edge[j].to ;
			if(!visit[t]&&dis[t]>edge[j].w) dis[t]=edge[j].w ;
		}
	}
	return true;
}

int main(){
	n=read();
	fill(dis,dis+n+1,INF);	
	m=read();
	for(int i=1;i<=m;i++){
		int u,v,w;
		u=read();
		v=read();
		w=read();
		add(u,v,w);
		add(v,u,w);
	}
	bool u=prim();
	if(!u){
		cout<<"orz"<<endl;
		return 0;
	}
	cout<<ans<<endl;
	return 0;
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define MAXN 1000010
#define INF 10000010

using namespace std;

inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

struct Edge{
    int to;
    int next;
    int w;
}edge[MAXN];

int n;
int m;
int head[MAXN];
int cnt=0;
int dis[MAXN];
int ans;
int visit[MAXN];

inline void add(int u,int v,int w){
    cnt++;
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt;
}

bool prim(){
    dis[1]=0;
    for(int i=1;i<=n;i++){
        int u=-1;
        int min=INF;
        for(int j=1;j<=n;j++){
            if(min>dis[j]&&!visit[j]){
                u=j;
                min=dis[j];
            }
        }
        if(u==-1){
            return false;
        }
        visit[u]=true;
        ans+=dis[u];
        for(int j=head[u];j;j=edge[j].next ){
            int t=edge[j].to ;
            if(!visit[t]&&dis[t]>edge[j].w) dis[t]=edge[j].w ;
        }
    }
    return true;
}

int main(){
    n=read();
    fill(dis,dis+n+1,INF);    
    m=read();
    for(int i=1;i<=m;i++){
        int u,v,w;
        u=read();
        v=read();
        w=read();
        add(u,v,w);
        add(v,u,w);
    }
    bool u=prim();
    if(!u){
        cout<<"orz"<<endl;
        return 0;
    }
    cout<<ans<<endl;
    return 0;
}
 

链式向前星

<think>嗯,用户想了解C++中的最小生成树。首先,我得回忆一下什么是最小生成树。最小生成树是图论中的一个概念,指的是在一个带权的连通图中,选取一部分边,使得这些边构成一棵树,并且所有边的权值之和最小。这样生成的树就叫最小生成树,简称MST。常用的算法有Prim算法和Kruskal算法。 接下来,我需要考虑如何在C++中实现这两种算法。首先,用户可能对这两种算法的原理不太清楚,所以需要先简要介绍一下它们的原理,然后再讲实现步骤。 Prim算法是从一个顶点开始,逐步扩展,每次选择当前已选顶点集合到未选顶点集合的最小权边,直到所有顶点都被包含。而Kruskal算法则是按边的权值从小到大选择,如果加入该边不会形成环,就加入,直到选n-1条边。 在C++中实现的话,Prim算法通常用优先队列(堆)来优化,这样时间复杂度可以降到O(E log V)。而Kruskal算法则需要用到并查集(Disjoint Set Union, DSU)来高效判断是否形成环,时间复杂度也是O(E log E)。 然后,数据结构方面,Prim算法可能需要邻接表或邻接矩阵来存储图,而Kruskal算法需要存储边的列表,并按权值排序。对于不同的图结构(比如稠密图或稀疏图),选择不同的算法会更高效。比如,Prim在稠密图中表现更好,而Kruskal在稀疏图中更合适。 用户可能需要具体的代码示例。那得分别写两个算法的示例代码。写的时候要注意代码的清晰性和正确性,比如在Prim算法中,如何维护优先队列,如何处理已访问的节点;在Kruskal中,如何实现并查集的路径压缩和按秩合并。 另外,要提到这两种算法的时间复杂度,以及它们的适用场景。可能还需要对比一下两者的优缺点,帮助用户选择适合自己情况的算法。 用户的问题可能还包括如何输入图的数据结构,比如边的表示方式,或者如何处理无向图。在代码示例中,应该包含这些细节,比如用结构体表示边,或者在Prim中使用邻接表存储每个顶点的相邻顶点和权重。 最后,需要检查一下是否有常见的错误需要注意,比如在Kruskal中忘记排序边,或者在Prim中没有正确更新优先队列中的边权值。另外,确保代码示例中的变量命名清晰,注释适当,方便用户理解。 总结一下,回答的结构应该是:先介绍最小生成树的概念,然后分别讲解Prim和Kruskal算法的原理,接着给出C++的实现代码,并解释关键部分,最后比较两种算法,给出适用场景的建议。这样用户就能逐步理解并选择合适的算法来解决问题。</think>### C++ 最小生成树(Minimum Spanning Tree, MST)介绍 最小生成树是**连通无向带权图**中权值总和最小的生成树。常见算法有 **Prim算法** 和 **Kruskal算法**,二者均基于贪心策略。以下分步讲解它们的原理与C++实现。 --- #### 一、Prim算法 **核心思想**:从任意顶点出发,逐步扩展树,每次选择连接**已选顶点集合**和**未选顶点集合**的最小权边。 **C++实现步骤**: 1. 使用**优先队列**(最小堆)存储候选边。 2. 用数组`visited`标记已访问的顶点。 3. 重复选择权值最小的边,并更新候选边。 ```cpp #include <iostream> #include <vector> #include <queue> using namespace std; typedef pair<int, int> pii; // {weight, vertex} int primMST(vector<vector<pii>> &graph, int start) { int n = graph.size(); priority_queue<pii, vector<pii>, greater<pii>> pq; vector<bool> visited(n, false); int totalWeight = 0; pq.push({0, start}); while (!pq.empty()) { auto [w, u] = pq.top(); pq.pop(); if (visited[u]) continue; visited[u] = true; totalWeight += w; for (auto &[v, weight] : graph[u]) { if (!visited[v]) { pq.push({weight, v}); } } } return totalWeight; } // 示例用法 int main() { int n = 5; vector<vector<pii>> graph(n); graph[0].push_back({1, 2}); // 顶点0到1,权重2 graph[0].push_back({3, 6}); graph[1].push_back({2, 3}); graph[1].push_back({3, 8}); graph[1].push_back({4, 5}); graph[2].push_back({4, 7}); cout << "Prim MST总权值: " << primMST(graph, 0) << endl; return 0; } ``` **时间复杂度**:$$ O(E \log V) $$(使用优先队列优化) --- #### 二、Kruskal算法 **核心思想**:按边权从小到大排序,依次选择不形成环的边,直到选$$ V-1 $$条边。 **C++实现步骤**: 1. 将边按权值排序。 2. 使用**并查集(DSU)**判断是否形成环。 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; struct Edge { int u, v, w; Edge(int u, int v, int w) : u(u), v(v), w(w) {} }; class DSU { vector<int> parent, rank; public: DSU(int n) { parent.resize(n); rank.resize(n, 0); for (int i = 0; i < n; i++) parent[i] = i; } int find(int x) { if (parent[x] != x) parent[x] = find(parent[x]); return parent[x]; } bool unite(int x, int y) { x = find(x), y = find(y); if (x == y) return false; if (rank[x] < rank[y]) parent[x] = y; else { parent[y] = x; if (rank[x] == rank[y]) rank[x]++; } return true; } }; int kruskalMST(vector<Edge> &edges, int n) { sort(edges.begin(), edges.end(), [](Edge &a, Edge &b) { return a.w < b.w; }); DSU dsu(n); int totalWeight = 0, count = 0; for (auto &e : edges) { if (dsu.unite(e.u, e.v)) { totalWeight += e.w; if (++count == n-1) break; } } return totalWeight; } // 示例用法 int main() { vector<Edge> edges = { Edge(0, 1, 2), Edge(0, 3, 6), Edge(1, 2, 3), Edge(1, 3, 8), Edge(1, 4, 5), Edge(2, 4, 7) }; cout << "Kruskal MST总权值: " << kruskalMST(edges, 5) << endl; return 0; } ``` **时间复杂度**:$$ O(E \log E) $$(主要由排序决定) --- #### 三、算法对比与选择 | 算法 | 适用场景 | 数据结构 | 时间复杂度 | |----------|------------------|----------------|------------------| | Prim | 稠密图(边多) | 邻接表 + 堆 | $$ O(E \log V) $$ | | Kruskal | 稀疏图(边少) | 边列表 + 并查集| $$ O(E \log E) $$ | --- #### 四、注意事项 1. 确保图为**连通图**,否则无法生成MST。 2. 图中**不能有自环**或**负权边**(根据具体实现可能允许)。 3. 在Kruskal中,排序边的权值是关键步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值