【图论】【最小生成树】【Prim】【Kruskal】最优布线问题

D e s c r i p t i o n Description Description

学校有n台计算机,为了方便数据传输,现要将它们用数据线连接起来。两台计算机被连接是指它们之间有数据线连接。由于计算机所处的位置不同,因此不同的两台计算机的连接费用往往是不同的。
当然,如果将任意两台计算机都用数据线连接,费用将是相当庞大的。为了节省费用,我们采用数据的间接传输手段,即一台计算机可以间接的通过若干台计算机(作为中转)来实现与另一台计算机的连接。
现在由你负责连接这些计算机,你的任务是使任意两台计算机都连通(不管是直接的或间接的)。

I n p u t Input Input

第一行为整数n(2<=n<=100),表示计算机的数目。此后的n行,每行n个整数。第x+1行y列的整数表示直接连接第x台计算机和第y台计算机的费用。

O u t p u t Output Output

一个整数,表示最小的连接费用。

S a m p l e I n p u t Sample Input SampleInput
3
0 1 2
1 0 1
2 1 0
S a m p l e O u t p u t Sample Output SampleOutput
2

注:表示连接1和2,2和3,费用为2)

思路

2019.4.25.今天有事,思路明天再写,先放代码

P r i m Prim Prim思路

1 1 1开始找 1 1 1能够到达的且距离最短的点
然后更新到其他没到达的点的距离
再找没有到达过的且距离最短的点
如此循环……

P r i m Prim Prim邻接矩阵
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define INF 10000
using namespace std;
int F[225][225],B[225],K[225];
//F代表两点距离
//B表示有没有到达过
//K表示当前离每个点的最短距离
int Ans,n,m,x,y;
int main()
{
	scanf("%d",&n);
	memset(F,0x3f,sizeof(F));
	memset(K,0x3f,sizeof(K));
	memset(B,0,sizeof(B));
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			scanf("%d",&F[i][j]);
	K[1]=0;//
	for(int i=1;i<=n;++i)
	{
		int k=0;
		for(int j=1;j<=n;++j)
			if(!B[j] && K[k]>K[j])k=j;//如果没到达且距离比当前点的距离小
		B[k]=1,Ans+=K[k];//加上距离且判定为到过
		for(int j=1;j<=n;++j)
			if(!B[j])K[j]=min(F[k][j],K[j]);//更新还没到过的点的最短距离
	}
	printf("%d",Ans);
	return 0;
}
P r i m Prim Prim邻接表
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define INF 10000
using namespace std;
int B[225],K[225],h[225];
int Ans,n,m,t,tot;
struct whw
{
	int w,x,h;
}wh[20025];
void hw(int x,int y,int s)
{
	wh[++tot]=(whw){y,s,h[x]};h[x]=tot;
	wh[++tot]=(whw){x,s,h[y]};h[y]=tot;
}
int main()
{
	scanf("%d",&n);
	memset(K,0x3f,sizeof(K));
	memset(B,0,sizeof(B));
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
		{
			scanf("%d",&t);
			if(i<j)hw(i,j,t);
		}
	K[1]=0;
	for(int i=1;i<=n;++i)
	{
		int k=0;
		for(int j=1;j<=n;++j)
			if(!B[j] && K[k]>K[j])k=j;
		B[k]=1,Ans+=K[k];
		for(int j=h[k];j;j=wh[j].h)
		//与邻接矩阵最主要的区别。到达一个点,只可能更新与此相连的点的最短距离
			if(!B[wh[j].w])K[wh[j].w]=min(wh[j].x,K[wh[j].w]);
	}
	printf("%d",Ans);
	return 0;
}

K r u s k a l Kruskal Kruskal思路

因为求得是最小的边和
所以我们就把边排序
然后对边进行判断
如果不在一个集合里的话
就放在一起
注:
这里用到了并查集

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct whw
{
	int x,s,y;
}wh[100025];
int n,t,k,x,y;
long long Ans;
int Fa[225];
int Find(int k)//并查集
{
	while(Fa[k]!=k)k=Fa[k];
	return k;
}
bool Cmp(whw i,whw j)//从小到大
{return i.s<j.s;}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
		{
			scanf("%d",&k);
			if(i<j)wh[++t].x=i,//因为有重复的,所以只用建一半的边
			wh[t].s=k,wh[t].y=j;
		}
	sort(wh+1,wh+t+1,Cmp);
	for(int i=1;i<=n;++i)Fa[i]=i;
	for(int i=1;i<=t;++i)
	{
		x=Find(wh[i].x);
		y=Find(wh[i].y);
		if(x!=y)//判断是否在一个集合
		{
			Fa[max(x,y)]=Fa[min(x,y)];
			Ans=Ans+(long long)wh[i].s;
		}
	}
	printf("%lld",Ans);
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值