【图论】次小生成树

Prim的:

#include<bits/stdc++.h>
#define ll int
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn=1005;
ll dis[maxn][maxn];
ll used[maxn][maxn];ll pre[maxn];ll Max[maxn][maxn];ll vis[maxn];
ll lowcost[maxn];
ll n,m;

ll prim(ll x){
	int sum=0;vis[x]=1;pre[x]=-1;
	for(int i=1;i<=n;i++){
		lowcost[i]=dis[x][i];
		pre[i]=x;
	}
	for(int i=1;i<n;i++){
		int mind=INF,minid=0;
		for(int j=1;j<=n;j++){
			if(!vis[j]&&mind>lowcost[j]){
				mind=lowcost[j];
				minid=j;
			}
		}
		if(mind==INF) return -1;
		sum+=mind;
		vis[minid]=1;
		used[minid][pre[minid]]=used[pre[minid]][minid]=1;
		for(int j=1;j<=n;j++){
			if(vis[j]&&j!=minid) Max[j][minid]=Max[minid][j]=max(Max[j][pre[minid]],lowcost[minid]);
			if(!vis[j]&&lowcost[j]>dis[minid][j]){
				lowcost[j]=dis[minid][j];
				pre[j]=minid;
			}
		}
	}	
	return sum;
}
int SP(int MST){
	int ans=INF;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			if(!used[i][j]&&dis[i][j]!=INF) ans=min(ans,MST-Max[i][j]+dis[i][j]);
		}
	}
	return ans;
}
int main(){
	cin>>n>>m;
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=n;j++){
			dis[i][j]=INF;
		}
	}
	ll u,v,w;
	for(ll i=1;i<=m;i++){
		cin>>u>>v>>w;
		if(w<dis[u][v]) dis[u][v]=dis[v][u]=w;
	}
	ll MST=prim(1);
	int S_M=SP(MST);
	cout<<S_M<<endl;
}
/*
5 5
1 2 5
2 3 1
3 4 2
2 4 3
4 5 5
*/

Kruskal的:

#include<bits/stdc++.h>
#define ll int
#define endl '\n'
using namespace std;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn=1005;
ll n,m,fa[maxn];
vector<int> G[maxn];
int Max[maxn][maxn];
struct node{
	ll u,v,w;
	bool vis;
}edge[maxn<<2];

bool cmp(node a,node b){
	return a.w<b.w;
}

inline ll find(ll x){
	while(x!=fa[x]) x=fa[x]=fa[fa[x]];
	return x;
}

int Kruskal(){
	ll eu,ev,cnt,ans=0;;
	sort(edge+1,edge+m+1,cmp);
	for(int i=1;i<=n;i++){
		G[i].clear();
		G[i].push_back(i);
	}
	for(ll i=1;i<=m;i++){
		eu=find(edge[i].u),ev=find(edge[i].v);
		if(eu==ev) continue;
		edge[i].vis=true;
		ans+=edge[i].w;
		for(int j=0;j<G[eu].size();j++){
			for(int k=0;k<G[ev].size();k++){
				Max[G[eu][j]][G[ev][k]]=Max[G[ev][k]][G[eu][j]]=edge[i].w;
			}
		}
		fa[ev]=eu;
		for(int j=0;j<G[eu].size();j++){
			G[ev].push_back(G[eu][j]);						
		}
		if(++cnt==n-1) break;
	}
	return ans;
}
int S_K(int MST){
	int ans=INF;
	for(int i=1;i<=m;i++){
		if(!edge[i].vis) ans=min(ans,MST+edge[i].w-Max[edge[i].u][edge[i].v]);
	}
	return ans;
}
int main(){
	cin>>n>>m;
	for(ll i=1;i<=n;i++) fa[i]=i;
	for(ll i=1;i<=m;i++) {cin>>edge[i].u>>edge[i].v>>edge[i].w;edge[i].vis=false;}
	int MST=Kruskal();
	int S_M=S_K(MST);
	cout<<S_M<<endl;
}
/*
5 5
1 2 5
2 3 1
3 4 2
2 4 3
4 5 5
*/

对于prim算法的,我每次更新的是Max[i][j],即是i到j这一段里面最大的一段长度。因为要凑环然后替换环中最大的边嘛

对于Kruskal算法,我们记录的是它的父亲节点到其的最大段距离,因为我们已经sort过了,从小到大排序,所以保障后面的一定比前面的大。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值