大家好,我是清墨,欢迎收看《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 个整数是 。
数据范围
-
对于 60% 的数据, 1≤n≤3且0≤
≤10。
-
对于 80% 的数据, 1≤n≤10且0≤
≤100。
-
对于 100% 的数据, 1≤n≤20且0≤
≤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分,为什么呢?
首先可以算一下算法复杂度是×2。
这必然是超了的,我们的C++程序复杂度最多也不能超过。
实验
我们先来研究一下这类题,实验出真知。
两个点
设直线上有两点(和
),兔子的地方。
如下图所示:
此时,应设在哪里才能使得总距离最短呢?《10秒时间思考》
9,3,1,0时间到,眼尖的同学能看出想要距离最短就要设在到
间的任意一点。
三个点
设直线上有两点(和
以及
),兔子的地方。
如下图所示:
此时,应设在哪里才能使得总距离最短呢?《还是10秒时间思考》
9,7,3,1,0时间到。
不知道上题眼尖的同学能不能看出来。
首先总距离拆分成两个部分
1.(和
之间)
想使第一部分最短只用设在和
之间任意一点就可以了
2.()
想使第二部分最短只用设在就可以了
这两个条件是完全不冲突的。可以说条件1包含条件2,满足条件2就是最优解。
所以设在就可以了。
四个点
设直线上有两点(和
以及
和
),兔子的地方。
如下图所示:
此时,应设在哪里才能使得总距离最短呢?不知道同学们能不能看出来。
首先总距离拆分成两个部分
1.(和
之间)
想使第一部分最短只用设在和
之间任意一点就可以了
2.(和
之间)
想使第二部分最短只用设在和
之间任意一点就可以了
这两个条件一样是完全不冲突的。可以说条件1包含条件2,满足条件2就是最优解。
所以设在和
之间任意一点就可以了。
或许大家看到这已经有点烦了,可以适当休息一下。
五个点
设直线上有两点(和
以及
和
还有
),兔子的地方。
如下图所示:
此时,应设在哪里才能使得总距离最短呢?不知道同学们能不能看出来。
首先总距离拆分成三个部分
1.(和
之间)
想使第一部分最短只用设在和
之间任意一点就可以了
2.(和
之间)
想使第二部分最短只用设在和
之间任意一点就可以了
3.()
想使第二部分最短只用设在就可以了
这三个条件一样是完全不冲突的。可以说条件1包含条件2,条件2包含条件3,满足条件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;
}
练一练.最小距离和
题目描述
给出一个数组 ,
......
你需要寻找一个整数b , 使得
最小,输出该最小值。
其中 absabs 是求绝对值。
输入格式
第一行,一个整数 nn,( 1≤n≤105 ) 。
第二行,nn 个整数,第 ii 个整数是 。( 1≤
≤109 )。
输出格式
一个整数。
思路.最小距离和
首先,我们学的是这第一期学的是的最小值。
对比一下和
,我们可以通过减法的性质,将
变为
而我们一样求的是b,
问你们是可以提前确定的,所以说,可以写出,下述程序。
#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;而已,所以我们做信息学时要多多变通,不要太死板,硬套公式。
我们下期再见。