C++进阶课程第1期——中位数

大家好,我是清墨,欢迎收看《C++进阶课程——中位数》。

停更了一个多月了,啊,我也废话不多说了,直接开始!

我们先了解一下中位数吧。

中位数的概念

 中位数是一组数据中的中间值,即将数据按照大小的顺序排列,如果数据的数量是奇数,则中位数是中间的那个数如果数据的数量是偶数,则中位数是中间两个数的平均值。中位数可以用来描述数据的集中趋势,它不受极端值的影响,相对于平均数更能代表数据的中心位置。在统计学中,中位数常用来衡量一组数据的分布的倾斜程度。

举个栗子(奇数个)

例如数列1,3,4,3,5.

① 按从小到大排序,可得1,3,3,4,5.

②得中位数是3.

再举个栗子(偶数个)

例如数列1,3,4,7,5,2.

① 按从小到大排序,可得1,2,3,4,5,7.

②得中位数是(3+4)÷2=3.5.

中位数例题

理解了中位数的特点,接下来,看一下例题吧。

GC.2020.六年级.02.兔子(rabbit)

题目描述

从左往右有 100000001100000001 个整数点,分别是整数点 00 至整数点 100000000100000000。有 nn 只兔子,第 ii 只兔子在整数点 didi​。

你需要选择一个整数点作为喂食点,所有兔子都要走到这个整数点进食。应该如何选择喂食点,才能使得所有兔子走过的总路程最小?

输出最小的总路程。

输入格式

第一行,一个整数n

第二行,共n个整数,第 i 个整数是 d_{i}

数据范围

  • 对于 60% 的数据, 1≤n≤3且0≤d_{i}≤10。

  • 对于 80% 的数据, 1≤n≤10且0≤d_{i}≤100。

  • 对于 100% 的数据, 1≤n≤20且0≤d_{i}≤108。

输出格式

一个整数。

这是我们桂城的真题。

《看看暴力枚举要怎样做吧》

兔子,暴力枚举法

//兔子,暴力枚举法
#include<bits/stdc++.h>
using namespace std;
int n,d[21];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
    {
		scanf("%d",&d[i]);
	}
	long long ans=LONG_MAX, sum;
	for(int i=0;i<=1e8;i++)
    {
		sum=0;
		for(int j=1;j<=n;j++)
        {
			sum+=abs(d[j]-i);
		}
		if(sum<ans)ans=sum;
	}
	cout<<ans;
	return 0;
}

这种暴力枚举的方法只有40分,为什么呢?

首先可以算一下算法复杂度是10^{9}×2。

这必然是超了的,我们的C++程序复杂度最多也不能超过10^{8}

实验

我们先来研究一下这类题,实验出真知。

两个点

设直线上有两点(x_{1}x_{2}),兔子的地方。

如下图所示:

此时,应设在哪里才能使得总距离最短呢?《10秒时间思考》

9,3,1,0时间到,眼尖的同学能看出想要距离最短就要设在x_{1}x_{2}间的任意一点

三个点

设直线上有两点(x_{1}x_{2}以及x_{3}),兔子的地方。 

如下图所示:

 

此时,应设在哪里才能使得总距离最短呢?《还是10秒时间思考》

9,7,3,1,0时间到。

不知道上题眼尖的同学能不能看出来。

首先总距离拆分成两个部分

1.(x_{1}x_{3}之间)

想使第一部分最短只用设在x_{1}x_{3}之间任意一点就可以了

2.(x_{2}

想使第二部分最短只用设在x_{2}就可以了

这两个条件是完全不冲突的。可以说条件1包含条件2,满足条件2就是最优解。

所以设在x_{2}就可以了。

四个点

设直线上有两点(x_{1}x_{2}以及x_{3}x_{4}),兔子的地方。 

如下图所示:

此时,应设在哪里才能使得总距离最短呢?不知道同学们能不能看出来。

首先总距离拆分成两个部分

1.(x_{1}x_{4}之间)

想使第一部分最短只用设在x_{1}x_{4}之间任意一点就可以了

2.(x_{2}x_{3}之间)

想使第二部分最短只用设在x_{2}x_{3}之间任意一点就可以了

这两个条件一样是完全不冲突的。可以说条件1包含条件2,满足条件2就是最优解。

所以设在x_{2}x_{3}之间任意一点就可以了。

或许大家看到这已经有点烦了,可以适当休息一下。

五个点

设直线上有两点(x_{1}x_{2}以及x_{3}x_{4}还有x_{5}),兔子的地方。 

如下图所示:

此时,应设在哪里才能使得总距离最短呢?不知道同学们能不能看出来。

首先总距离拆分成三个部分

1.(x_{1}x_{5}之间)

想使第一部分最短只用设在x_{1}x_{4}之间任意一点就可以了

2.(x_{2}x_{4}之间)

想使第二部分最短只用设在x_{2}x_{3}之间任意一点就可以了

3.(x_{3}

想使第二部分最短只用设在x_{3}就可以了

这三个条件一样是完全不冲突的。可以说条件1包含条件2,条件2包含条件3,满足条件3就是最优解。

所以设在x_{3}之间任意一点就可以了。

结论

 当2只兔子时,在两只兔子间。

当3只兔子时,在中间的兔子那里。

 当4只兔子时,在中间两只兔子间。

当5只兔子时,在中间的兔子那里。

......

中位数出来了!

桂城题目兔子解法

#include<bits/stdc++.h>
using namespace std;
int n,a[100000001];
int minn=INT_MAX,mini;
int x,y;
int f(int x)//求距离和的函数
{
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        sum=sum+abs(x-a[i]);
    }
    return sum;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    sort(a+1,a+1+n);//排序求中位数第一步
    y=(n+1)/2;//求中位数第二步
    cout<<f(a[y])<<" ";
    return 0;
}

 练一练.最小距离和 

题目描述

给出一个数组 a_{1},a_{2}......a_{n}你需要寻找一个整数b , 使得

\sum_{1}^{n}abs(a_{i}-(b+i))最小,输出该最小值。

其中 absabs 是求绝对值。

输入格式

第一行,一个整数 nn,( 1≤n≤105 ) 。

第二行,nn 个整数,第 ii 个整数是 a_{i}。( 1≤a_{i}≤109 )。

输出格式

一个整数。

思路.最小距离和 

 首先,我们学的是这第一期学的是\sum_{1}^{n}abs(a_{i}-b)的最小值。

对比一下\sum_{1}^{n}abs(a_{i}-b)\sum_{1}^{n}abs(a_{i}-(b+i)),我们可以通过减法的性质,将\sum_{1}^{n}abs(a_{i}-(b+i))变为\sum_{1}^{n}abs(a_{i}-i-b)而我们一样求的是b,a_{i}-i问你们是可以提前确定的,所以说,可以写出,下述程序。

#include<bits/stdc++.h>
using namespace std;
int n,a[100001],minn,t;
long long f(long long x)
{
    long long sum=0;
    for(int i=1;i<=n;i++)
    {
        sum=sum+abs(x-a[i]);
    }
    return sum;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>t;
        a[i]=t-i;
    }
    sort(a+1,a+1+n);
    int w=n/2+n%2;
    cout<<f(a[w]);
    return 0;
}

也就只多了句 a[i]=t-i;而已,所以我们做信息学时要多多变通,不要太死板,硬套公式。

我们下期再见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值