最小生成树 - Prim算法

本文详细介绍了Prim算法,一种用于求解无向加权图中最短生成树的贪心策略。通过步骤、时间复杂度和伪代码演示了如何使用Prim算法解决实际问题,如HDU_7058中的墨点连通问题。特别强调了如何将问题转化为求最长边的平方作为答案。
摘要由CSDN通过智能技术生成

最小生成树 - Prim算法

思路:

采用 贪心策略,每次选取连通块外延的最短边和对应的点放入连通块,再更新新的连通块外延的边。连通部分逐渐扩大,最后将整个图连通起来,并且边长之和最小
时间复杂度:O( n ^ 2 ),应用于稠密图

伪代码 / 模板:

int prim(){
    memset(dist,INF,sizeof dist); //dist[i]表示i节点到连通块的最短路径
	//st[i]标记i节点是否在连通块内
    int ans=0;
    for(int i=0;i<n;i++){
        int hp=-1;
        for(int j=1;j<=n;j++){ //寻找到连通块最近的点
            if(!st[j]&&(hp==-1||dist[hp]>dist[j]))
                hp=j;
        }
        if(i&&dist[hp]==INF) //不连通
            return INF;
        if(i)
            ans+=dist[hp];
        st[hp]=true;
        for(int j=1;j<=n;j++){ //更新外延边
            dist[j]=min(dist[j],mp[hp][j]);
        }
    }
    return ans; //最小边长和
}

模板题:AcWing858. Prim算法求最小生成树

题面:(传送门)

题面

思路:

模板题还需要思路? 见前文模板代码注释。

AC代码:

#include<iostream>
#include<cstring>
using namespace std;
const int N=505;
const int INF=0x3f3f3f3f;

int n,m;
int mp[N][N];
int dist[N];
bool st[N];

int prim(){
	memset(dist,INF,sizeof dist);
	
	int ans=0;
	for(int i=0;i<n;i++){
		int hp=-1;
		for(int j=1;j<=n;j++){
			if(!st[j]&&(hp==-1||dist[hp]>dist[j]))
				hp=j;
		}
		if(i&&dist[hp]==INF)
			return INF;
		if(i)
			ans+=dist[hp];
		st[hp]=true;
		for(int j=1;j<=n;j++){
			dist[j]=min(dist[j],mp[hp][j]);
		}
	}
	
	return ans;
}

int main(){
	
	//freopen("D:\\in.txt","r",stdin);
	
	cin>>n>>m;
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)
				mp[i][j]=1;
			else
				mp[i][j]=INF;
		}
	}
	
	int u,v,w;
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&u,&v,&w);
		mp[u][v]=mp[v][u]=min(mp[u][v],w);
	}	
	
	int ans=prim();
	if(ans==INF)
		cout<<"impossible"<<endl;
	else
		cout<<ans<<endl;
	
	return 0;
} 

应用题:HDU_7058. Ink on paper

题面:(传送门)

题面

思路:

因为任意两滴墨点只要时间足够都会联通
两个墨点双向奔赴即速度为 1 c m / s 1cm/s 1cm/s
墨点间的距离为 ( x 1 − x 2 ) ∗ ( x 1 − x 2 ) + ( y 1 − y 2 ) ∗ ( y 1 − y 2 ) \sqrt{(x_{1}-x_{2})*(x_{1}-x_{2})+(y_{1}-y_{2})*(y_{1}-y_{2})} (x1x2)(x1x2)+(y1y2)(y1y2)
但答案要求输出最短时间的平方
综上,任意两墨点联通 的时间的平方 即 答案 为 ( x 1 − x 2 ) ∗ ( x 1 − x 2 ) + ( y 1 − y 2 ) ∗ ( y 1 − y 2 ) (x_{1}-x_{2})*(x_{1}-x_{2})+(y_{1}-y_{2})*(y_{1}-y_{2}) (x1x2)(x1x2)+(y1y2)(y1y2)
题目就可以转换为:求 所有墨点的完全图 的最小生成树 中的最长的边hu 大喘气

AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N=5005;
const long long LLF=9e18;

int n;
int st[N];
long long mp[N][N];
long long dist[N];

struct Node{
	long long x,y;
}e[N];

int main(){
	
	//freopen("D:\\in.txt","r",stdin);
	
	int T;
	cin>>T;
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%lld%lld",&e[i].x,&e[i].y);
			dist[i]=LLF;
			st[i]=0;
		}
		
		long long hp;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(i!=j){
					hp=(e[i].x-e[j].x)*(e[i].x-e[j].x)+(e[i].y-e[j].y)*(e[i].y-e[j].y);
					mp[i][j]=hp;
				}
			}
		}
		
		dist[1]=0;
		long long ans=-1;
		for(int i=0;i<n;i++){
			hp=-1;
			for(int j=1;j<=n;j++)
				if(!st[j]&&(hp==-1||dist[hp]>dist[j]))
					hp=j;
			st[hp]=1;
			ans=max(ans,dist[hp]);
			for(int j=1;j<=n;j++)
				dist[j]=min(dist[j],mp[hp][j]);
		}
		cout<<ans<<endl;
	}
	return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值