寒假预备役每周总结(2.15)

放假回来的第一天,也是直接开刷本周的任务,感觉很顺利(可能是沉淀了太久),下面发一下今天刷题的题解

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

解题思路:将每个点之间的距离算出来(勾股定理)用结构体存储点与点之间的距离关系,依据点与点之间的距离将其排成升序(距离远就用卫星电话),遍历结构体,判断该点是否被连通过,确定循环边界,输出答案

代码实现:

#include<stdio.h>
#include<math.h>
#define N 510
int f[N];
int a[N],b[N];
int s,p;
int k,sum;
double res;
struct node//定义结构体
{
	int x;
	int y;
	double z;
 }arr[1000000];
void init()//初始化函数
{
	for(int i=1;i<=p;i++)
		f[i]=i;
}
int find(int x)//并查集中的“查”
{
	if(x==f[x])
		return x;
	else
	{
		f[x]=find(f[x]);
		return f[x];
	}
}
void qsort(int l,int r)//快排函数
{
	double temp=arr[(l+r)/2].z;
	int i=l,j=r;
	while(1)
	{
		if(i>=j)
			break;
		while(arr[j].z>temp)
			j--;
		while(arr[i].z<temp)
			i++;
		if(i<=j)
		{
			struct node temp1=arr[i];
			arr[i]=arr[j];
			arr[j]=temp1;
			i++;
			j--;
		}
	}
	if(j>l)
		qsort(l,j);
	if(i<r)
		qsort(i,r);
}
int main()
{
	scanf("%d %d",&s,&p);
	init();
	for(int i=1;i<=p;i++)
	{
		scanf("%d %d",&a[i],&b[i]);
		for(int j=1;j<i;j++)
		{
			arr[++k].x=i;
			arr[k].y=j;
			arr[k].z=sqrt((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j]));//勾股定理求两点之间的距离
		}
	}
//	for(int i=1;i<=k;i++)
//		printf("%d %d %.2lf\n",arr[i].x,arr[i].y,arr[i].z);
//	printf("截止\n");
	qsort(1,k);
//	for(int i=1;i<=k;i++)
//		printf("%d %d %.2lf\n",arr[i].x,arr[i].y,arr[i].z); 
	for(int i=1;i<=k;i++)
	{
		int t1=find(arr[i].x);
		int t2=find(arr[i].y);
		if(t1!=t2)//判断是否连接过
		{
			sum++;
			f[t2]=t1;
			res=arr[i].z;
			if(sum==p-s)//出循环条件
			{
				printf("%.2lf",res);
				return 0;
			}	
		 } 
	}
 } 

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

解题思路:题目要求经过道路的拥挤度最大值的最小(直接排成升序),遍历结构体,每遍历一次就判断一次是否能到达目的地,能就直接输出当前遍历到的拥挤度,否则继续遍历,直到能到目的地即可

代码实现:

#include<stdio.h>
#define N 20010
int n,m,s,t;
int f[N];
struct node//定义结构体
{
	int x;
	int y;
	int z;
}a[1000000];
int find(int x)//并查集中的“查”
{
	if(x==f[x])
		return x;
	else
	{
		f[x]=find(f[x]);
		return f[x];
	}
}
void init()//初始化函数
{
	for(int i=1;i<=n;i++)
		f[i]=i;
}
int qsort(int l,int r)//快排函数
{
	int temp=a[(l+r)/2].z;
	int i=l,j=r;
	while(1)
	{
		if(i>=j)
			break;
		while(a[j].z>temp)
			j--;
		while(a[i].z<temp)
			i++;
		if(i<=j)
		{
			struct node temp1=a[i];
			a[i]=a[j];
			a[j]=temp1;
			i++;
			j--;
		}
	 }
	if(j>l)	
		qsort(l,j);
	if(i<r)
		qsort(i,r);
}
int pd()//判断函数
{
	if(find(f[s])==find(f[t]))
		return 1;
	else
		return 0;
}
int main()
{
	scanf("%d %d %d %d",&n,&m,&s,&t);
	init();//初始化
	for(int i=1;i<=m;i++)
		scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].z);
	qsort(1,m);//排序
//	for(int i=1;i<=m;i++)
//		printf("%d ",a[i].z);
	for(int i=1;i<=m;i++)
	{
		int t1=find(a[i].x);
		int t2=find(a[i].y);
		if(t1!=t2)
			f[t2]=t1;
		if(pd())//满足条件就输出
		{
			printf("%d",a[i].z);
			return 0;
		}
	} 
}

题目链接:P2872 [USACO07DEC] Building Roads S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

解题思路:跟无线通讯网很像,先把每个点之间的距离用勾股定理算出来,再将其排成升序,遍历结构体,这里要注意的是题目给了我们部分边,要把这些边变成0,或者把这两个点合并(两钟都可以,只是出循环的条件不同而已)

代码实现:

第一种:将已知成边的两点合并

#include<stdio.h>
#include<math.h>
#define N 1010
int f[N];
int n,m,k;
int a1[N],a2[N];
double res;
struct node//定义结构体
{
	int x;
	int y;
	double z;//距离要用浮点型
}a[1000000];
void init()//初始化函数
{
	for(int i=1;i<=n;i++)
		f[i]=i;
}
int find(int x)//并查集
{
	if(x==f[x])
		return x;
	else
	{
		f[x]=find(f[x]);
		return f[x];
	}
}
int qsort(int l,int r)//快排函数
{
	double temp=a[(l+r)/2].z;
	int i=l,j=r;
	while(1)
	{
		if(i>=j)
			break;
		while(a[j].z>temp)
			j--;
		while(a[i].z<temp)
			i++;
		if(i<=j)
		{
			struct node temp1=a[i];
			a[i]=a[j];
			a[j]=temp1;
			i++;
			j--;
		}
	}
	if(j>l)
		qsort(l,j);
	if(i<r)
		qsort(i,r);
}
int pd()//判断函数
{
	int sum=0;
	for(int i=1;i<=n;i++)
		if(f[i]==i)
		{
			sum++;
			if(sum==2)
				return 0;
		}
	return 1;
}
int main()
{
	scanf("%d %d",&n,&m);
	init(); 
	for(int i=1;i<=n;i++)
	{
		scanf("%d %d",&a1[i],&a2[i]);
		for(int j=1;j<i;j++)
		{
			a[++k].x=i;
			a[k].y=j;
			a[k].z=sqrt((double)(a1[i]-a1[j])*(double)(a1[i]-a1[j])+(double)(a2[i]-a2[j])*(double)(a2[i]-a2[j]));//勾股定理求距离,这里在sqrt里面要用到强制转换将其转换成浮点型
		}
	}
	for(int i=1;i<=m;i++)//合并已经成边的两个点(也可以将其边变成0存入结构体中)
	{
		int u,v;
		scanf("%d %d",&u,&v);
		int t1=find(u);
		int t2=find(v);
		f[t2]=t1;
	}
	qsort(1,k);
//	for(int i=1;i<=k;i++)
//		printf("%d %d %.2lf\n",a[i].x,a[i].y,a[i].z);
//	printf("\n");
	for(int i=1;i<=k;i++)//这里的循环条件为k而不是n,找了好久都没找到!!!
	{
		int t1=find(a[i].x);
		int t2=find(a[i].y);
		if(t1!=t2)
		{
			f[t2]=t1;
			res+=a[i].z;
			if(pd())
			{
				printf("%.2lf",res);
				return 0;
			}
		}
	}
 } 

第二种:将已经成边的两点的边变成0存入结构体数组中

#include<stdio.h>
#include<math.h>
#define N 1010
int f[N];
int n,m,k;
int a1[N],a2[N];
double res;
int flog;//判断整个图是否联通
struct node//定义结构体
{
	int x;
	int y;
	double z;
}a[1000000];
void init()//初始化函数
{
	for(int i=1;i<=n;i++)
		f[i]=i;
}
int find(int x)//并查集
{
	if(x==f[x])
		return x;
	else
	{
		f[x]=find(f[x]);
		return f[x];
	}
}
int qsort(int l,int r)//快排函数
{
	double temp=a[(l+r)/2].z;
	int i=l,j=r;
	while(1)
	{
		if(i>=j)
			break;
		while(a[j].z>temp)
			j--;
		while(a[i].z<temp)
			i++;
		if(i<=j)
		{
			struct node temp1=a[i];
			a[i]=a[j];
			a[j]=temp1;
			i++;
			j--;
		}
	}
	if(j>l)
		qsort(l,j);
	if(i<r)
		qsort(i,r);
}
int main()
{
	scanf("%d %d",&n,&m);
	init();
	for(int i=1;i<=n;i++)
	{
		scanf("%d %d",&a1[i],&a2[i]);
		for(int j=1;j<i;j++)
		{
			a[++k].x=i;
			a[k].y=j;
			a[k].z=sqrt((double)(a1[i]-a1[j])*(double)(a1[i]-a1[j])+(double)(a2[i]-a2[j])*(double)(a2[i]-a2[j]));//勾股定理求两点间距离
		}
	}
	for(int i=1;i<=m;i++)//将输入的已成边的长度变成0
	{
		int u,v;
		scanf("%d %d",&u,&v);
		a[++k].x=u;
		a[k].y=v;
		a[k].z=0;
	}
	qsort(1,k);
//	for(int i=1;i<=k;i++)
//		printf("%d %d %.2lf\n",a[i].x,a[i].y,a[i].z);
//	printf("\n");
	for(int i=1;i<=k;i++)//循环条件为k而不是n
	{
		int t1=find(a[i].x);
		int t2=find(a[i].y);
		if(t1!=t2)
		{
			f[t2]=t1;//合并两点
			res+=a[i].z;
			flog++;
			if(flog==n-1)//出循环边界
			{
				printf("%.2lf",res);
				return 0;
			}
		}
	}
 } 

以上两种处理方式都可以ac,多写一种方法也能锻炼我们的能力,对最小生成树的理解也会更加深刻

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值