练习题解(关于最小生成树)

目录

1.【模板】最小生成树

2.无线通讯网

3.拆地毯

4.营救


1.【模板】最小生成树

P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz

输入格式

第一行包含两个整数 N,M,表示该图共有 N 个结点和 M 条无向边。

接下来 M 行每行包含三个整数Xi​,Yi​,Zi​,表示有一条长度为 Zi​ 的无向边连接结点 Xi​,Yi​。

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

输入输出样例

输入 #1

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

输出 #1

7

数据范围

1≤N≤5000,1≤M≤2×10^5,1≤Zi​≤10^4。

既然说是是模版题,那么我们直接套用Kruskal算法或者Prim算法的,这里我们使用Kruskal算法,如果有不清楚这两种算法的可以看我上一篇作品。

这里我们给出核心函数:

void Kruskal()
{
	sort(a+1,a+1+m,cmp);
	for(int i=1;i<=m;i++){
		int fx=Find(a[i].x);
		int fy=Find(a[i].y);
		if(fx==fy) continue;
		pre[fx]=fy;
		ans+=a[i].w;
		cnt++;
		if(cnt==n-1)
		break; 
	}
}

利用c++的sort函数将边按照从小到大排序看,便可以完美解决。

下面是完整AC代码:

#include
using namespace std;
struct node{
	int x,y,w;
}a[200010];
int n,m,ans=0,cnt=0;
int pre[6000];
int Find(int x)
{
	if(pre[x]==x) return x;
	return pre[x]=Find(pre[x]);
}
bool cmp(node &x,node &y)
{
	return x.w>n>>m;
	for(int i=1;i<=n;i++){
		pre[i]=i;//初始化 
	}
	for(int i=1;i<=m;i++){
		cin>>a[i].x>>a[i].y>>a[i].w;
	}
	Kruskal();//进入核心代码 
	if(cnt==n-1)
	cout<

2.无线通讯网

P1991 无线通讯网 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

国防部计划用无线网络连接若干个边防哨所。2 种不同的通讯技术用来搭建无线网络;

每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。

任意两个配备了一条卫星电话线路的哨所(两边都有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过 D,这是受收发器的功率限制。收发器的功率越高,通话距离 D 会更远,但同时价格也会更贵。

收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个 D。你的任务是确定收发器必须的最小通话距离 D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。

输入格式

第一行,2 个整数 S 和 P,S 表示可安装的卫星电话的哨所数,P 表示边防哨所的数量。

接下里 P 行,每行两个整数 x,y 描述一个哨所的平面坐标(x,y),以 km 为单位。

输出格式

第一行,1 个实数 D,表示无线电收发器的最小传输距离,精确到小数点后两位。

数据范围

1≤S≤100,S

这道题我一开始没有看懂,到后面经过高人指导才了解,我们需要输出最小的传输距离的前提是这些距离可以联通覆盖所有放哨点,卫星电话就是不管距离多远也可以传输,就不用无线电收发器。

还是使用Kruskal算法,我感觉这道题的边排序与Kruskal算法蛮适合。

看数据范围,P表示放哨所的数量,那我们的边最多是P*P,所以给代表边的结构体数组开范围需要开大一些。

边的长度可以利用数学知识(勾股定理)来求。

double dist(double x1,double y1,double x2,double y2)
{
	return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
}

其他的就是存边操作。

	for(int i=1;i<=m;i++){
		for(int j=i+1;j<=m;j++){
			a[++re].x=i;
			a[re].y=j;
			a[re].w=dist(x[i],y[i],x[j],y[j]);
		}
	}

下面是完整AC代码。

#include
using namespace std;
int pre[600];
struct node{
	int x,y;
	double w;
}a[300000];
int x[600],y[600],re;
double ans[300000];
double dist(double x1,double y1,double x2,double y2)
{
	return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
}
int Find(int x)
{
	if(pre[x]==x) return x;
	return pre[x]=Find(pre[x]);
}
bool cmp(node &k1,node &k2)
{
	return k1.w>n>>m;
	for(int i=1;i<=m;i++){
		cin>>x[i]>>y[i];
		pre[i]=i;
	}
	for(int i=1;i<=m;i++){
		for(int j=i+1;j<=m;j++){
			a[++re].x=i;
			a[re].y=j;//存边 
			a[re].w=dist(x[i],y[i],x[j],y[j]);
		}
	}
	sort(a+1,a+1+re,cmp);
	int cnt=0;
	for(int i=1;i<=re;i++){
		int fx=Find(a[i].x);
		int fy=Find(a[i].y);
		if(fx==fy) continue;
		pre[fx]=fy;
		cnt++;
		if(cnt==m-n)//减去n是因为多出的n可以使用卫星电话 
		{
			printf("%.2lf\n",a[i].w);
			return 0;
		}
	}

	return 0;
} 

3.拆地毯

P2121 拆地毯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

会场上有 n 个关键区域,不同的关键区域由 m 条无向地毯彼此连接。每条地毯可由三个整数 u、v、w 表示,其中 u 和 v 为地毯连接的两个关键区域编号,w 为这条地毯的美丽度。

由于颁奖典礼已经结束,铺过的地毯不得不拆除。为了贯彻勤俭节约的原则,组织者被要求只能保留至多 K 条地毯,且保留的地毯构成的图中,任意可互相到达的两点间只能有一种方式互相到达。换言之,组织者要求新图中不能有环。现在组织者求助你,想请你帮忙算出这至多 K 条地毯的美丽度之和最大为多少。

输入格式

第一行包含三个正整数 n、m、K。

接下来 m 行中每行包含三个正整数 u、v、w。

输出格式

只包含一个正整数,表示这 K 条地毯的美丽度之和的最大值。

输入输出样例

输入 #1

5 4 3
1 2 10
1 3 9
2 3 7
4 5 3

输出 #1

22

数据范围

1<=n,m,k<=100000

这道题其实就是将边的排序改成从大到小,这样才能得到最大美丽度之和。

其他的就和模板体一样。

下面是完整AC代码:

#include
using namespace std;
struct node{
	int x,y,w;
}a[100010];
int n,m,ans=0,cnt=0,k;
int pre[100010];
int Find(int x)
{
	if(pre[x]==x) return x;
	return pre[x]=Find(pre[x]);
}
bool cmp(node &x,node &y)
{
	return x.w>y.w;
}
void Kruskal()
{
	sort(a+1,a+1+m,cmp);
	for(int i=1;i<=m;i++){
		int fx=Find(a[i].x);
		int fy=Find(a[i].y);
		if(fx==fy) continue;//如果在一个集合就跳过 
		pre[fx]=fy;
		ans+=a[i].w;
		cnt++;
		if(cnt==k)//当加入的边k
		break; 
	}
}
int main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		pre[i]=i;//初始化 
	}
	for(int i=1;i<=m;i++){
		cin>>a[i].x>>a[i].y>>a[i].w;
	}
	Kruskal();//进入核心代码 
	cout<

4.营救

P1396 营救 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

妈妈下班回家,街坊邻居说小明被一群陌生人强行押上了警车!妈妈丰富的经验告诉她小明被带到了 t 区,而自己在 s 区。

该市有 m 条大道连接 n 个区,一条大道将两个区相连接,每个大道有一个拥挤度。小明的妈妈虽然很着急,但是不愿意拥挤的人潮冲乱了她优雅的步伐。所以请你帮她规划一条从 s 至 t 的路线,使得经过道路的拥挤度最大值最小。

输入格式

第一行有四个用空格隔开的 n,m,s,t,其含义见【题目描述】。

接下来 m 行,每行三个整数 u,v,w,表示有一条大道连接区 u 和区 v,且拥挤度为 w。

输出格式

输出一行一个整数,代表最大的拥挤度。

输入输出样例

输入 #1

3 3 1 3
1 2 2
2 3 1
1 3 3

输出 #1

2

数据范围

保证 1≤n≤10^4,1≤m≤2×10^4,w≤10^4,1≤s,t≤n。且从 s 出发一定能到达 t 区。

因为这道题需要的是拥挤度最大值最小,所以我们只需输出当s区与t区联通的时候的拥挤度即可。

下面是完整AC代码:

#include
using namespace std;
struct node{
	int x,y,w;
}a[20010];
int n,m,ans=0,s,e;
int pre[10010];
int Find(int x)
{
	if(pre[x]==x) return x;
	return pre[x]=Find(pre[x]);
}
bool cmp(node &x,node &y)
{
	return x.w>n>>m>>s>>e;
	for(int i=1;i<=n;i++){
		pre[i]=i;//初始化 
	} 
	for(int i=1;i<=m;i++){
		cin>>a[i].x>>a[i].y>>a[i].w;
	}
	cout<

你可能感兴趣的:(算法,数据结构,图论)