ccf 数据中心 prim+邻接链表+堆100分

这道题网上大多是用kruskal做的,因为准备ccf的关系,准备学习c++,于是希望实现prim练练手,写博客来积累一下学到的数据结构。这道题题意就是求最小生成树中权值最大的边。因为它给的数据量问题,是个边稀疏图,用kruskal做效率更高,但是优化的prim也可以做到满分。prim+邻接链表+堆实现。堆中存放的是边,用pair表示,first表示边权值,second表示到达点的序号。cou...
摘要由CSDN通过智能技术生成

这道题网上大多是用kruskal做的,因为准备ccf的关系,准备学习c++,于是希望实现prim练练手,写博客来积累一下学到的数据结构。

这道题题意就是求最小生成树中权值最大的边。因为它给的数据量问题,是个边稀疏图,用kruskal做效率更高,但是优化的prim也可以做到满分。
prim+邻接链表+堆实现。

堆中存放的是边,用pair表示,first表示边权值,second表示到达点的序号。count表示已访问过的顶点个数,n表示顶点总个数

核心逻辑是:
1.入堆一个虚拟边,权值为0,到达点为起始点。
2.弹出堆顶元素,若second访问过了,则continue,若没有访问过,则count++,res = first
3.if count == n then return res
4.将所有到达点未访问过的邻接边入堆 ,goto 2

误区(就是我开始写错了):在4中判断过到达点未访问过,所以不用在2中判断second是否已经访问过,这是不对的。原因是循环的判断顺序是按照权值的,而不是入堆的顺序,所以可能在之前判断未访问过的到达点边,在出堆的时候已经访问过了。

#include<bits/stdc++.h>
using namespace std;
/*
prim算法
*/
typedef pair<int,int> wl;
//默认第一关键字排序,这里的空格是必要的,否则会成移位符 greater表示升序队列,即小顶堆 
priority_queue <wl,vector<wl>,greater<wl> >q;
struct Edge{
	int nextNode;
	int cost;
};
const int N = 100001;
vector<Edge> edge[N];
const int MAXV = 500001;
bool visited[MAXV] = {false};//表示是否已经拜访
int prim(int root,int n){
	q.push(make_pair(0,1));
	int res = 0,count = 0;
	while(!q.empty()){
		int u = q.top().second;
		int v = q.top().first;
		q.pop();
		if(visited[u]){
			continue;
		}
		
		count++;
		res = res>v?res:v;//这里多此一举了,应该只需要res = v;
		if(count==n){
			return res;
		}
		visited[u] = true;
		for(int i  = 0;i<edge[u].size();i++){
			if(!visited[edge[u][i].nextNode]){
				q.push(make_pair(edge[u][i].cost,edge[u][i].nextNode));
			}	
		}
	} 
	return 0;
}
int main(){
	int n,m,root;
	int u,v,w;
	scanf("%d",&n);
	scanf("%d",&m);
	scanf("%d",&root);
	for(int i = 0;i<m;i++){
		scanf("%d %d %d",&u,&v,&w);
		Edge temp1,temp2;
		temp1.nextNode = v;
		temp1.cost = w;
		temp2.nextNode = u;
		temp2.cost = w;
		edge[u].push_back(temp1);
		edge[v].push_back(temp2);
	}
	printf("%d\n",prim(root,n));
	return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值