烦恼的高考志愿(之前发的太简单了,再来一遍详细版)

烦恼的高考志愿

烦恼的高考志愿 链接

题意

要求我们为每位学生推荐一所学校,使得学校的预计分数线和学生的估分相差最小,这个最小值为不满意度。我们需要求所有学生不满意度和的最小值。

思路

首先,我们需要将学校的预计分数线进行排序。
然后,对于每位学生,我们使用二分查找算法找到第一个大于或等于学生估分的学校分数线,记为a[l]。
接下来,我们判断学生估分是否小于等于排序后的第一个学校的分数线a[0],或者是否大于等于排序后的最后一个学校的分数线a[m-1]。如果是,我们直接计算不满意度并累加到总和中。
如果不是,我们计算学生估分与a[l]和a[l-1]的差值,取最小值作为不满意度,并累加到总和中。
最后,输出总和作为最小的不满度之和。

坑点

  1. 在使用二分查找算法时,需要注意边界条件。在查找第一个大于或等于学生估分的学校分数线时,需要正确地处理区间的划分。在本题中,使用了(l+r)>>1的方式计算中点,需要注意这种方式的正确性。

算法一:排序+二分查找

时间复杂度

O(nlogn)

实现步骤

首先,通过 cin>>m>>n; 读取了学校数 m 和学生数 n。
使用 for(int i=0;i<m;i++) cin>>a[i]; 读取了 m 所学校的预计录取分数,存储在数组 a 中。
使用 for(int i=0;i<n;i++) cin>>b[i]; 读取了 n 位学生的估分成绩,存储在数组 b 中。
接下来,使用 sort(a,a+m); 对学校的预计录取分数进行升序排序。这一步是为了满足题目中的要求,即对于每个学生,需要找到与其估分相差最小的学校预计分数线。
然后,使用 for(int i=0;i<n;i++) 遍历每个学生,进行二分查找,找到与其估分相差最小的学校预计分数线。a. 首先,通过 int l=0,r=m-1; 初始化二分查找的左边界 l 和右边界 r。b. 在 while(l<r) 循环中,使用 int mid=l+r>>1; 计算当前区间的中点 mid。c. 使用 if(a[mid]>=b[i]) r=mid; 更新右边界 r,使其等于当前区间的中点 mid。d. 使用 else l=mid+1; 更新左边界 l,使其等于当前区间的中点 mid 加1。e. 通过上述步骤,循环结束后,左边界 l 就是第一个大于或等于学生估分的学校分数线。
在找到学校分数线后,通过 if(a[l]==b[i]) continue; 跳过与估分相等的情况。
使用 if(b[i]<=a[0]) 和 if(b[i]>=a[m-1]) 判断学生估分是否小于等于排序后的第一个学校的分数线 a[0],或者是否大于等于排序后的最后一个学校的分数线 a[m-1]。如果是,直接计算不满意度并累加到总和中。
如果不是,使用 sum+=min(abs(b[i]-a[l]),abs(b[i]-a[l-1])); 计算学生估分与 a[l] 和 a[l-1] 的差值,取最小值作为不满意度,并累加到总和中。
最后,使用 cout<<sum<<endl; 输出最小的不满度之和。

代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[1000005];
int b[1000005];
//定义了两个长度为1000005的数组a和b,
//用于存储学校的预计录取分数和学生的估分成绩 
int m,n;//定义了两个整型变量m和n,
//用于存储学校的数量和学生的数量。 
long long int sum;
// 定义了一个长整型变量sum,
//用于存储所有学生的不满意度和
int main()
{
        cin>>m>>n;//从输入流中读取m和n的值 
        for(int i=0;i<m;i++){
         cin>>a[i];
         }
        //m 个学校的预计录取分数,存储在数组 a 中。
        for(int i=0;i<n;i++){
         cin>>b[i];
         }
        //输入 n 个学生的估分成绩,存储在数组 b 中
        sort(a,a+m);//使用sort函数对数组a进行排序 
        for(int i=0;i<n;i++)    //一个for循环,遍历数组b,对于每个学生的估分,使用二分查找法在数组a中查找最接近的学校的预计分数线
        {
                int l=0,r=m-1;// // 对于每个学生,初始化二分查找的左边界l为0,右边界r为学校的数量m减1
                while(l<r)
                {// 当左边界小于右边界时,进行二分查找
                        int mid=l+r>>1;
                        // 找到中间位置的学校预计录取分数
                        if(a[mid]>=b[i]) r=mid;
                        else l=mid+1;
                }//二分
                if(a[l]==b[i]) continue;
                if(b[i]<=a[0]) {
                        sum+=abs(b[i]-a[0]);
                        continue;
                }
                if(b[i]>=a[m-1]){
                        sum+=abs(b[i]-a[m-1]);//(abs:绝对值)
                        continue;
                }
                sum+=min(abs(b[i]-a[l]),abs(b[i]-a[l-1]));
                //abs(b[i]-a[l])表示学生 i 的估分 b[i] 与学校 l 的预计分数线,学校 l-1 的预计分数线 a[l-1] 之间的差的绝对值。
        }

    //如果找到了与估分相等的学校的预计分数线,那么直接跳过,因为我们要找的是在a中大于等于b[i]的最小元素。
    //如果估分小于等于数组a的第一个元素,那么距离和就是估分与数组a的第一个元素之间的距离。
    //如果估分大于等于数组a的最后一个元素,那么距离和就是估分与数组a的最后一个元素之间的距离。
    //否则,距离和就是估分与在a中大于等于估分的最小元素之间的距离和估分与在a中小于等于估分的最大元素之间的距离中的较小值。
        cout<<sum<<endl;
        //输出距离和
        return 0;
}

 

总结

关于学生填报大学的问题。题目中给出了 m 所学校的预计分数线和一个学生的估分。要求为每位学生推荐一所学校,使得学生的估分与学校的预计分数线之间的差距最小。最后求出所有学生与学校之间的差距总和的最小值。
简单来说,就是为学生找一个最合适的学校,使得他们估分和学校分数线之间的差距总和最小。

  • 42
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值