信息学奥赛初赛天天练-75-NOIP2016普及组-完善程序-二分答案、二分查找、贪心算法、贪心策略

1 完善程序 (单选题 ,每小题3分,共30分)

郊游活动

有 n名同学参加学校组织的郊游活动,已知学校给这 n名同学的郊游总经费为 A元,与此同时第 i位同学自己携带了 Mi 元。为了方便郊游,活动地点提供 B(≥n) 辆自行车供人租用,租用第 j辆自行车的价格为 Cj元,每位同学可以使用自己携带的钱或者学校的郊游经费,为了方便账务管理,每位同学只能为自己租用自行车,且不会借钱给他人,他们想知道最多有多少位同学能够租用到自行车。(第四、五空 2.5 分,其余 3分)

本题采用二分法。对于区间 [l,r],我们取中间点 mid 并判断租用到自行车的人数能否达到 mid。判断的过程是利用贪心算法实现的。

源程序

#include <iostream>
using namespace std;
01 #define MAXN 1000000
02 
03 int n, B, A, M[MAXN], C[MAXN], l, r, ans, mid;
04 
05 bool check(int nn) {
06 	int count = 0, i, j;
07 	i = ①;
08 	j = 1;
09 	while (i <= n) {
10 		if(②)
11 			count += C[j] - M[i];
12 		i++;
13 		j++;
14 	}
15 	return ③;
16 }
17 	
18 void sort(int a[], int l, int r) {
19 	int i = l, j = r, x = a[(l + r) / 2], y;
20 	while (i <= j) {
21 		while (a[i] < x) i++;
22 		while (a[j] > x) j--;
23 		if (i <= j) {
24 			y = a[i]; a[i] = a[j]; a[j] = y;
25 			i++; j--;
26 		}
27 	}
28 if (i < r) sort(a, i, r);
29 if (l < j) sort(a, l, j);
30 }
31 
32 int main() {
33 	int i;
34 	cin >> n >> B >> A;
35 	for (i = 1; i <= n; i++)
36 		cin >> M[i];
37 	for (i = 1; i <= B; i++)
38 		cin >> C[i];
39 	sort(M, 1, n);
40 	sort(C, 1, B);
41 	l = 0;
42 	r = n;
43 	while (l <= r) {
44 		mid = (l + r) / 2;
45 		if(④){
46             ans = mid;
47 			l = mid + 1;
48 		}else
49 			r = ⑤;
50 	}
51 	cout << ans << endl;
52 	return 0;
53 }

1 ①处应填( )

2 ②处应填( )

3 ③处应填( )

4 ④处应填( )

5 ⑤处应填( )

2 相关知识点

二分答案

二分答案顾名思义,它用二分的方法枚举答案,并且枚举时判断这个答案是否可行

直接对答案进行枚举查找,接着判断答案是否合法。如果合法,就将答案二分进一步靠近,如果不合法,就接着二分缩小判断。这样就可以大大的减少时间。

二分中有时可以得可行得答案,但不是最大的,继续向右靠近,求出最大值

 int ans = 1;
 int l = 1,r = 100000;//在1~100000之间的整数枚举 
 while(l <= r){
     int m = l + (r - l) / 2;
     if(check(m)){//满足 则进行向右缩小范围 看看有没有更大的 
         ans = m;//可能多次赋值 最后一定是可能的最大值 
         l = m + 1;
      }else{//不满足缩小边长 向左缩小范围 用更小边长继续尝试 
         r = m - 1;
	  } 
  }

二分找边界

//左闭右闭 while left right 最终left=right+1
while(left<=right)  left = mid + 1; right =mid-1;
//左闭右开 while left right 最终left=right
while(left<right)   left = mid + 1; right =mid;
//左开右闭 while left right 最终left=right
while(left<right)   left=mid;       right=mid-1;
//左开右开 while left right 最终left=right-1
while(left+1<right) left=mid;       right=mid;

二分查找时间复杂度

二分查找每次都缩小或扩大为原来的一半,所以也是Olog(n)

贪心算法

所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择 。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的 局部最优解

例题

某商店不能电子支付,钱柜里的货币只有 25 分、10 分、5 分和 1 分四种硬币,如果你是售货员且要找给客户 41 分钱的硬币,如何安排才能找给客人的钱既正确且硬币的个数又最少?

分析

钱币保证最大面额大于其他小于它的面额之和,保证了每次选择最大的没有其他优于这个组合

即 选择了25 即使选择10+5+1=16都比25小

每次选择找零面额最大的,每次都是本次最优(局部最优),根据钱币面额本身的性质可知,可以保证全局最优

3 思路分析

求最多有多少位同学能够租用到自行车,总共n位同学,1~n 位同学之间二分的方法判定是否可以能租

判定是否可以租,使用贪心算法,具体如下

贪心策略,较多钱的同学去租相对便宜的车

//判定nn位同学是否可以租到自行车
05 bool check(int nn) {
06 	int count = 0, i, j;
07 	i = ①;//n-nn+1 取钱较多的nn个人 贪心算法
08 	j = 1;//租车费用从小到大租,贪心算法
09 	while (i <= n) {
10 		if(②)//M[i]<C[j] 如果当前同学带的钱不够,累加起来,看看学校经费是否够
11 			count += C[j] - M[i];
12 		i++;
13 		j++;
14 	}
15 	return ③;//count<=A 看学校经费是否够 ,经费够可以租nn辆车,经费不够不能租nn辆车
16 }

1 ①处应填( n-nn+1 )

分析

07 	i = ①;//n-nn+1 取钱较多的nn个人 贪心算法
例如
n=10 nn=6 
从10-6+1=5,到10这6个人
因为前面按从小到大进行了排序
5~10这6人,比1~6这6人有钱

2 ②处应填( M[i]<C[j] )

分析

10 		if(②)//M[i]<C[j] 如果当前同学带的钱不够,累加起来,看看学校经费是否够
如果钱带的够,就可以租n辆车
为了让钱不够的同学租到车,需要从学校经费借钱,把借的钱累加起来,后续判定是否超出经费

3 ③处应填( count<=A )

分析

15 	return ③;//count<=A 看学校经费是否够 ,经费够可以租nn辆车,经费不够不能租nn辆车

4 ④处应填( check(mid) )

分析

/*二分思想,计算左右边界的中间租车数量,如果可以组,看看能否可以租更多,如果不能租,看看少租一些车是否可行
mid = (l + r) / 2;
check(mid)
*/
43 	while (l <= r) {
44 		mid = (l + r) / 2;
45 		if(④){
46             ans = mid;
47 			l = mid + 1;
48 		}else
49 			r = ⑤;
50 	}

5 ⑤处应填( mid-1 )

分析

二分边界,如下为左右闭区间,l=mid+1,r=mid-1
所以填mid-1
43 	while (l <= r) {
posted @ 2024-08-25 16:47  new-code  阅读(25)  评论(0编辑  收藏  举报