【每日亿题:洛谷1257】平面上的最接近点对(学习c艹stl库vector和pair模板)

第一次写博客先来个签到题试一下水doge:

提示:纯小白,大佬勿喷(qwq

  • 一周掌握蓝桥杯入门算法(1/7)

题面

点击---->直达洛谷

题目描述

给定平面上 nnn 个点,找出其中的一对点的距离,使得在这 nnn 个点的所有点对中,该距离为所有点对中最小的。
输入格式

第一行一个整数 nnn,表示点的个数。

接下来 nnn 行,每行两个实数 x,yx,yx,y ,表示一个点的行坐标和列坐标。
输出格式

仅一行,一个实数,表示最短距离,四舍五入保留 444 位小数。

输入输出样例
输入 #1

3
1 1
1 2
2 2

输出 #1

1.0000

说明/提示
数据规模与约定

对于 100% 的数据,保证 1≤n≤1041 \leq n \leq 10^41≤n≤104,0≤x,y≤1090 \leq x, y \leq 10^90≤x,y≤109,小数点后的数字个数不超过 666。

--------------------------------------华丽的分割线-------------------------------------

Let s Do It

方法一:喜闻乐见 暴力美学

     先求第一个点和后面每个点的距离
     再求第二个点和后面每个点的距离
     再求第三个点和后面每个点的距离
     ...
     求倒数第二个点到倒数第一个点的距离

每次求出来之后对比一下答案和每个距离的大小
如果有比答案还小的距离就把答案踢出去,换成它
这就搞完了!(doge)
时间复杂度 O(n^2) 数据最多只到10000,管那么多干嘛qwq能过就好(doge)

具体实现:

用vector向量数组把每个点存入进去,考虑到每个点有横坐标和纵坐标两个变量,于是再用stl库中的pair来给他俩牵红线:make_pair(x,y),然后存入vector中后来依次比较实现上述的算法就o了个k,容易想也容易实现;

#include<bits/stdc++.h>
using namespace std;
vector<pair<int,int>>a;
#define inf 0x5fffff
long double dis(int x1,int y1,int x2,int y2)
{
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
	long double ans=inf;
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		a.push_back(make_pair(x,y));
	}
	for(int i=0;i<n;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			long double d=dis(a[i].first,a[i].second,a[j].first,a[j].second);
			if(ans>=d)ans=d;
		}
	}
	cout<<fixed<<setprecision(4)<<ans<<endl;
}

方法二:分而治之(分治法)

1.按照x/y坐标升序排序(直接用库中的sort函数搞定)O(nlogn)根据下标进行分割成两个集合
2.递归寻找两个集合中的最近的点对,取最小值;
问题:有可能一个点在a集合一个点在b集合,他俩距离最小
3.那就先取两个集合中的最小值min,跟边界点左右两个点x坐标的平均值midx
划分出以一个[mid-min,mid+min],最小距离点对应该在这中间,所以用这个区间左半边的点跟右半边的点
tips:

#include<bits/stdc++.h>
using namespace std;
struct point
{
    double x,y;
}p[100086];
int n,t[100086];
bool cmp(const point &A,const point &B)
{
    if(A.x==B.x)
        return A.y<B.y;
    else
        return A.x<B.x;
}
bool cmps(const int &a,const int &b)
{
    return p[a].y<p[b].y;
}
double distance(int i,int j)
{
    return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
}
double merge(int left,int right)
{
    double dis=2<<20;
    if(left==right)
        return dis;
    if(left+1==right)
        return distance(left,right);
    int mid=(left+right)>>1;
    double d1=merge(left,mid);
    double d2=merge(mid+1,right);
    dis=min(d1,d2);
    int k=0;
    for(int i=left;i<=right;i++)
        if(fabs(p[i].x-p[mid].x)<=dis)
            t[k++]=i;
    sort(t,t+k,cmps);
    for(int i=0;i<k;i++)
        for(int j=i+1;j<k&&p[t[j]].y-p[t[i]].y<dis;j++)
            dis=min(dis,distance(t[i],t[j]));
    return dis; 
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
        scanf("%lf %lf",&p[i].x,&p[i].y);
    sort(p,p+n,cmp);
    printf("%.4lf\n",merge(0,n-1));
    return 0;
}
根据提供的两个引用,我们可以看出这是两个不同的C语言程序,分别用于解决洛谷上的B2097题目。这道题目的要求是找到一个数列中最长的连续相同的数的个数。 下面是第一个程序的解释: ```c #include<stdio.h> int main() { int x[200],y[200]; int n,i,max=0;//初始化max scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&x[i]); if(x[i]==x[i-1]) y[i]=y[i-1]+1;//核心,和前一项相关 else y[i]=1;//如果不是,归一 if(y[i]>max) max=y[i];//更新数据 } printf("%d",max); return 0; } ``` 这个程序的思路是,首先读入一个长度为n的数列,然后遍历这个数列,如果当前数和前一个数相同,则将当前数的计数器加1,否则将当前数的计数器归一。在遍历的过程中,记录下最大的计数器值,即为最长的连续相同的数的个数。最后输出这个最大值即可。 下面是第二个程序的解释: ```c #include<stdio.h> #include<math.h> #include<string.h> #include<stdlib.h> #include<stdbool.h> int main(){ int pro,next,n,sum=1,max; int i; scanf("%d",&n); scanf("%d",&pro); max=1; for(i=1;i<n;i++){ scanf("%d",&next); if(next==pro){ sum++; if(max<sum){ max=sum; } pro=next; } else{ pro=next; sum=1; } } printf("%d\n",max); return 0; } ``` 这个程序的思路是,首先读入一个长度为n的数列,然后遍历这个数列,如果当前数和前一个数相同,则将当前数的计数器加1,否则将当前数的计数器归一。在遍历的过程中,记录下最大的计数器值,即为最长的连续相同的数的个数。最后输出这个最大值即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值