• 最小生成树的prim和Kruskal算法


    最小生成树

    用最小的代价将图中的每一个点联通

    我们有两种基于贪心策略的算法

    Prim

    1. 初始化一点作为根节点

    2. 选择权值最小的与当前联通块相连的点加入到联通块中

    3. 如果图未遍历完成 则返回2

    Kruskal

    1. 初始化图中所以的边 并按权值进行排序

    2. 遍历边的数组 如果当前边所连两点不连通 则将其连接

    Prim代码

    #include<bits/stdc++.h> 
    
    using namespace std;
    
    const int maxn = 5050;
    const int maxm = 200020;
    int n,m;
    struct Edge{
    	int from;
    	int to;
    	ll cost;
    }edge[maxm];
    bool cmp(Edge a,Edge b)
    {
    	return a.cost<b.cost;
    }
    int fath[maxn];	//我们用并查集来维护当前两个点是否联通
    
    void init()
    {
    	for(int i=0;i<maxn;++i)	
    		fath[i] = i;
    }
    int find(int f)
    {
    	if(f==fath[f])	return f;
    	return fath[f] = find(fath[f]);
    }
    
    void unionSet(int a,int b)
    {
    	int u = find(a), v = find(b);
    	if(u==v)	return ;
    	fath[u] = v;
    }
    long long Kruskal()
    {
    	long long ans = 0;
    	for(int i=1;i<=m;++i)
    	{
    		if(find(edge[i].from)==find(edge[i].to))	continue;//如果联通,则跳过当前边
    		unionSet(edge[i].from,edge[i].to);	//两个点的集合合并
    		ans+=edge[i].cost;
    	}
    	return ans;
    }
    int main()
    {
    	cin >> n >> m;
    	for(int i=1;i<=m;++i)
    	{
    		cin>>edge[i].from >> edge[i].to>>edge[i].cost; 
    	}
    	init();
    	sort(edge+1,edge+1+m,cmp);
    	ll ans = Kruskal();
    
    	for(int i=1;i<=n;++i)
    	{
    		if(find(i)!=find(1))	ans = -1;
    	}//检查是否所以的点都联通
    	if(ans==-1)	cout << "orz" << endl;
    	else cout << ans<<endl;
    	return 0;
    }
    
    

    Kruskal代码

    
    #include<bits/stdc++.h> 
    
    using namespace std;
    
    const int maxn = 5050;
    const int maxm = 200020;
    int n,m;
    
    struct edge{
       int to;
       ll cost;
       edge(int tt,ll cc):to(tt),cost(cc){	}
       edge(){}
       bool operator<(const edge &a)const{	//维护小根堆
       	return a.cost<cost;
       }
    };
    
    bool vis[maxn];						//记录点是否加入
    priority_queue<edge> que;		
    vector<edge>		G[maxn];		//记录所有的边
       
    ll prim()
    {
       ll ans = 0;
       vis[1] = 1;			//初始化 将1号点作为初始点
       for(int i=0;i<G[1].size();++i)		//将所有的边加入堆中
       	que.push(G[1][i]);
       while(que.size())			
       {
       	edge e = que.top();	//获得当前最小的边
       	que.pop();
       	if(vis[e.to])	continue;	//如果加入则挑过
       	vis[e.to] = 1;
       	ans += e.cost;
       	for(int i=0;i<G[e.to].size();++i)	//将当前点所有的边加入堆中
       		que.push(G[e.to][i]); 
       }
       return ans;
    }
    int main()
    {
       cin >> n >> m;
       for(int i=0;i<=n;++i)
       	G[i].clear();
       while(que.size())	que.pop();
       for(int i=1;i<=m;++i)
       {
       	int u,v;
       	ll cost;
       	cin >> u >> v >>cost;
       	G[u].push_back(edge(v,cost));//无向图 两个点都要加入
       	G[v].push_back(edge(u,cost));
       }
       ll ans = prim();
       for(int i=1;i<=n;++i)
       {
       	if(!vis[i])	ans = -1;
       }
       if(ans==-1)	cout << "orz" <<endl;
       else 		cout << ans<<endl;
       return 0;
    
    } 
    
    
  • 相关阅读:
    以UIWebView的方式来播放网络多媒体档案
    Cocoa.Programming.for.Mac系统文章翻译
    iOS开发教程:Storyboard全解析第二部分
    boost日期、时间操作
    使用thrift大量编译警告消息方法
    一键自动往crontab添加条目脚本
    apache thrift的不足
    将Fedora 18 LXDE安装到U盘和进入图形界面的方法
    boost库thread.hpp编译警告(type attributes are honored only at type definition)已修复
    平板电视必知知识
  • 原文地址:https://www.cnblogs.com/xxrlz/p/10487032.html
Copyright © 2020-2023  润新知