prime算法与kruska算法随记

大佬写的详细讲解

例题

A - Jungle Roads
#include<stdio.h>
const int Max=105;
int INF=99999;
bool vis[Max];
int dis[Max];//边集合
int map[Max][Max];
int N;
void solve_data()
{
	for(int i=1;i<=N;i++){
		vis[i]=false;
		for(int j=1;j<=N;j++)
			if(i!=j) map[i][j]=INF;
			else map[i][j]=0;
	}
}
//输出调试查看 
void prin()
{
	printf("  ");
	for(int i=0;i<N;i++)
		printf("    %c",'A'+i);
	printf("\n");
	for(int i=1;i<=N;i++)
	{
		printf("%c:",'A'+i);
		for(int j=1;j<=N;j++)
		{
			if(map[i][j]==INF)
				printf("%5d",-1);
			else
				printf("%5d",map[i][j]);
		}
		printf("\n");
	}
}
void init()
{
	//使用%s读入能避免输入格式有误(多空格) 
	char str[105];
	for(int i=1;i<N;i++)
	{
		scanf("%s",str);
		int x=str[0]-'A'+1;
		int K;
		scanf("%d",&K);
		while(K--)
		{
			scanf("%s",str);
			int y=str[0]-'A'+1;
			scanf("%d",&map[x][y]);
			map[y][x]=map[x][y];
		}
	}
}
//最小生成树的起点:v 
void prime(int v)
{
	int ans=0;
	for(int i=1;i<=N;i++)
		dis[i]=map[v][i];
	vis[v]=true;
	for(int i=1;i<N;i++)
	{
		//从边集合里找到最短边 
		int Min=INF,min_id;
		for(int j=1;j<=N;j++)
			if(!vis[j]&&dis[j]<=Min)
				min_id=j,Min=dis[j];
		}
		//将最短边的点加入集合 
		vis[min_id]=true;
		ans+=Min;
		//将加入集合的点遍历,加入其它边到集合中 
		for(int j=1;j<=N;j++)
			if(!vis[j]&&map[min_id][j]<dis[j])
				dis[j]=map[min_id][j];
	}
	printf("%d\n",ans);
}
int main()
{
	while(scanf("%d",&N)!=EOF)
	{
		if(N==0)
			break;
		solve_data();
		init();
//		prin();
		prime(1);
	}
	
	
	return 0;
}
F - Arctic Network
//kruskal算法
/*
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int Max=505;
double INF=99999;
int S,N,n2;
bool vis[Max];
int f[Max];
int x[Max],y[Max];
double dis[Max];
double ans[Max];
//每条边的封装对象
struct node{
	int u,v;//第u个点到第v个点
	double len;//边长
}map[Max*Max];//记得开平方的大小(n条边需要相互连接)
//计算边长封装函数
double Len(int p,int q)
{
	int x1=x[p],y1=y[p];
	int x2=x[q],y2=y[q];
	int xx=x2-x1,yy=y2-y1;
	return sqrt(xx*xx+yy*yy);
}
//读入数据函数
void init()
{
	scanf("%d %d",&S,&N);
	for(int i=1;i<=N;i++)
		scanf("%d %d",&x[i],&y[i]);
}
//对边长进行排序的判断函数
bool cmp1(node x,node y)
{
	return x.len<y.len;
}
//对答案进行排序的判断函数
bool cmp2(double x,double y)
{
	return x>y;
}
//初始化kruskal算法需要用到的数据
void solve_data()
{
	//初始化并查集的节点的父节点
	for(int i=1;i<=N;i++)
		f[i]=i;
	//计算每条边的长度
	n2=1;
	for(int i=1;i<=N;i++)
		for(int j=1;j<=N;j++)
		{
			map[n2].u=i,map[n2].v=j;
			map[n2].len=Len(i,j);
			n2++;
		}
	//对边的长度进行排序
	sort(map+1,map+n2+1,cmp1);
}
//并查集的find函数(寻找并更新父节点)
int Find(int num)
{
	if(num==f[num])
		return num;
	return f[num]=Find(f[num]);
}
//并查集(本人英语较差,比较喜欢用中文命名函数)
bool bcj(int x,int y)//也可用merge命名
{
	int xx=Find(x),yy=Find(y);
	if(xx!=yy)
	{
		f[yy]=xx;
		return true;
	}
	return false;
}
//kruskal算法
void kruskal()
{
	//初始化数据
	solve_data();
	int cnt=0;
	for(int i=1;i<=n2;i++)
	{
		if(bcj(map[i].u,map[i].v))
		{//若未在
			cnt++;
			ans[cnt]=map[i].len;
		}
		//当录入了N-1条边时,跳出
		if(cnt==N-1)
			break;
	}
	//对录入的边进行排序
	sort(ans+1,ans+N,cmp2);
	printf("%.2f\n",ans[S]);
}
int main()
{
	int T;
	while(scanf("%d",&T)!=EOF)
		while(T--)
		{
			init();
			kruskal();
		}
	
	
	return 0;
}
*/
//prime算法

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int Max=505;
double INF=99999;
int S,N;
bool vis[Max];
double dis[Max];
double ans[Max];
struct node{
	int x,y;
}map[Max];
double Len(int p,int q)
{
	int x1=map[p].x,y1=map[p].y;
	int x2=map[q].x,y2=map[q].y;
	int xx=x2-x1,yy=y2-y1;
	return sqrt(xx*xx+yy*yy);
}
void init()
{
	scanf("%d %d",&S,&N);
	for(int i=1;i<=N;i++)
	{
		double xx,yy;
		scanf("%lf %lf",&xx,&yy);
		map[i].x=xx,map[i].y=yy;
	}
}
void prime()
{
	for(int i=1;i<=N;i++)
		vis[i]=false;
	vis[1]=true;
	for(int i=1;i<=N;i++)
		dis[i]=Len(1,i);
	
	for(int i=1;i<N;i++)
	{
		int min_id;
		double min=INF;
		for(int j=1;j<=N;j++)
			if(!vis[j]&&dis[j]<min)
				min=dis[j],min_id=j;
		vis[min_id]=true;
		ans[i]=min;
		
		for(int j=1;j<=N;j++)
			if(!vis[j]&&Len(min_id,j)<dis[j])
				dis[j]=Len(min_id,j);
	}
}
bool cmp(double x,double y)
{
	return x>y;
}
int main()
{
	int T;
	while(scanf("%d",&T)!=EOF)
		while(T--)
		{
			init();
			prime();
			sort(ans+1,ans+N,cmp);
			printf("%.2f\n",ans[S]);
		}
	
	
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值