最小生成树(模板)

最小生成树(MST):将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树。
数据结构:树形结构,或者说是直链型结构,因为当n个点相连,且路径和最短,那么将它们相连的路一定是n-1条
实现思路:将点分为在树中的点与不在树中的点,每次取出树中点的连接的最小路径,且该路径连接的点不在树中,然后将该路径连接的点加入树中,重复并进行路径更新,即松弛,当取出边达到n-1条时,树已建立。
洛谷P1546
求一条路径,使得u到v连通的路径的最小长度
(Prim算法)

本质上还是贪心思想。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=110;
const int Inf=0x3f3f3f3f;
int n;
int adj[maxn][maxn];
int cost[maxn],vis[maxn];
int prim(){
   for(int i=0;i<=n;i++){
	cost[i]=Inf;//0-n的花费都为无穷大
	vis[i]=0;//所有点都还没在集合里
   }
   cost[1]=0;//将1号点加入集合

   int res=0;//保存答案
  for(int i=1;i<=n;i++){
	int minn=0;//保存花费最小的下标
	for(int j=1;j<=n;j++){
		if(vis[j]==0&&cost[j]<cost[minn]){
			minn=j;//每次都要一个代价最小的
		}
	}
	vis[minn]=1;//将点加入集合
	res+=cost[minn];//代价及时加上去
	for(int i=1;i<=n;i++){//从选择的点出发,遍历所有的点,看看那些点的代价可以被改小
		if(!vis[i]&&cost[i]>adj[minn][i]){
			cost[i]=adj[minn][i];
		}
	}
  }
   return res;
}
int main(){
   cin>>n;
   for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	cin>>adj[i][j];
   cout<<prim()<<endl;
}

洛谷P3366

Kruskal算法:还是贪心思想。(sort+并查集)

#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=5005;
const int maxm=200205;
int father[maxn];
int n,m;
int mst;
struct node{
   int u,v,w;
   bool operator<(const node & n)const{
   	return w<n.w;//价值从小到大
   }
}g[maxm];

int find(int x){//找父亲结点。
   if(x==father[x])return x;
   return father[x]=find(father[x]);//路径压缩,把递归过程中遇到的
    //结点的祖宗结点也直接修改了。
}
void merge(int v,int u){
	father[find(v)]=find(u);//合并v,w.
}
bool k(){
     for(int i=1;i<=n;i++){
	father[i]=i;
    }
    int cnt;
    cnt=mst=0;
    sort(g,g+m);
    for(int i=0;i<m;i++){
	int u=g[i].u;
	int v=g[i].v;
	int w=g[i].w;
	if(find(u)!=find(v)){
	   mst+=w;
	   cnt++;
	   merge(u,v);
	    if(cnt==n-1)return true;
	}
    }
   
    return false;

}
int main(){
	cin>>n>>m;
    for(int i=0;i<m;i++){
      cin>>g[i].u>>g[i].v>>g[i].w;
    }
    if(k()){
	cout<<mst<<endl;
    }
    else cout<<"orz"<<endl;
   return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值