信息学奥赛初赛天天练-48-CSP-J2020完善程序2-变量交换、冒泡排序、贪心算法、最小区间覆盖

PDF文档公众号回复关键字:20240728

2020 CSP-J 完善程序2

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

最小区间覆盖

给出 n 个区间,第 i 个区间的左右端点是 [ai,bi]。现在要在这些区间中选出若干个,使得区间 [0, m] 被所选区间的并覆盖(即每一个 0≤i≤m 都在某个所选的区间中)。保证答案存在,求所选区间个数的最小值。

输入第一行包含两个整数 n 和 m (1≤n≤5000,1≤m≤10^9) 接下来 n 行,每行两个整数 ai,bi

(0≤ai,bi≤m)

提示:使用贪心法解决这个问题。先用 O(n^2) 的时间复杂度排序,然后贪心选择这些区间

01 #include <iostream>
02 using namespace std;
03 const int MAXN = 5000;
04 int n, m;
05 struct segment { int a, b; } A[MAXN];
06
07 void sort() // 排序
08 {
09   for (int i = 0; i < n; i++)
10       for (int j = 1; j < n; j++)
11           if (①)
12           {
13             segment t = A[j];
14             ②
15           }
16 }
17
18 int main()
19 {
20   cin >> n >> m;
21   for (int i = 0; i < n; i++)
22     cin >> A[i].a >> A[i]?b;
23   sort();
24   int p = 1;
25   for (int i = 1; i < n; i++)
26     if (③)
27       A[p++] = A[i];
28   n = p;
29   int ans =0, r = 0;
30   int q = 0;
31   while (r < m)
32   {
33     while (④)
34       q++;
35     ⑤;
36     ans++;
37   }
38   cout << ans << endl;
39   return 0;
40 }

39.①处应填( )[3分]

A.A[j].b>A[j-1].b

B.A[j].a<A[j-1].a

C.A[j].a>A[j-1].a

D.A[j].b<A[j-1].b

40.②处应填( )[3分]

A.A[j+1]=A[j];A[j]=t;

B.A[j-1]=A[j];A[j]=t;

C.A[j]=A[j+1];A[j+1]=t;

D.A[j]=A[j-1];A[j-1]=t;

41.③处应填( )[3分]

A.A[i].b>A[p-1].b

B.A[i].b<A[i-1].b

C.A[i].b>A[i-1].b

D.A[i].b<A[p-1].b

42.④处应填( )[3分]

A.q+1<n&&A[q+1].a<=r

B.q+1<n&&A[q+1].b<=r

C.q<n&&A[q].a<=r

D.q<n&&A[q].b<=r

43.⑤处应填( )[3分]

A.r=max(r,A[q+1].b)

B.r=max(r,A[q].b)

C.r=max(r,A[q+1].a)

D.q++

2 相关知识点

1) 冒泡排序

冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端

n个元素的冒泡排序,需要n趟完成,

每趟进行逐一两两比较,进行n-1次比较,把最大(最小)元素比较出来,交换到最后

2) 元素交换

int a=3;
int b=2;
int t;//通过t使a和b的值进行交换
t=a;
a=b;
b=t;

3) 贪心算法

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

例题

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

分析

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

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

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

3 思路分析

1) 按左端点从小到大排序

07 void sort() // 排序
08 {
09   for (int i = 0; i < n; i++)
10       for (int j = 1; j < n; j++)
11           if (A[j].a<A[j-1].a)
12           {
13             segment t = A[j];
14             A[j]=A[j-1];A[j-1]=t;
15           }
16 }

2) 排除包含区间,会重复计算

去除1)图中的3线段

25   for (int i = 1; i < n; i++)
26     if (A[i].b>A[p-1].b)
27       A[p++] = A[i];

3) 去除几条线段组合重复区间

贪心选择最靠右边的线段,找到下一个区间左端点小于当前右端点的最后一个线段

33     while (q+1<n&&A[q+1].a<=r)
34       q++;

如下图1,2,4覆盖的区间和1,4覆盖的区间相同,需要去除线段2

39.①处应填( B )[3分]

A.A[j].b>A[j-1].b

B.A[j].a<A[j-1].a

C.A[j].a>A[j-1].a

D.A[j].b<A[j-1].b

分析

冒泡排线,比较相邻2个线段左端点的大小,如果后边小则交换,保证从小到大排序

40.②处应填( D )[3分]

A.A[j+1]=A[j];A[j]=t;

B.A[j-1]=A[j];A[j]=t;

C.A[j]=A[j+1];A[j+1]=t;

D.A[j]=A[j-1];A[j-1]=t;

分析

2个元素交换

41.③处应填( A )[3分]

A.A[i].b>A[p-1].b

B.A[i].b<A[i-1].b

C.A[i].b>A[i-1].b

D.A[i].b<A[p-1].b

分析

去除后面被包含的线段,不去除会重复计算线段

比如下面情况:1,2,4和1,4覆盖区间相同的,需要把2去除,否则计算覆盖线段数会多一个

42.④处应填( A )[3分]

A.q+1<n&&A[q+1].a<=r

B.q+1<n&&A[q+1].b<=r

C.q<n&&A[q].a<=r

D.q<n&&A[q].b<=r

分析

1)找下一个线段,下一个线段的左端点必须在上个线段右端点左边,保证区间是连续的

2)贪心选择最靠右边的线段,找到下一个区间左端点小于当前右端点的最后一个线段

43.⑤处应填( B )[3分]

A.r=max(r,A[q+1].b)

B.r=max(r,A[q].b)

C.r=max(r,A[q+1].a)

D.q++

分析

找到下一个线段,延长覆盖区间的长度,即延长覆盖区间的右端点

posted @ 2024-07-28 20:02  new-code  阅读(14)  评论(0编辑  收藏  举报