信息学奥赛一本通 1324:【例6.6】整数区间
【題目鏈接】
ybt 1324:【例6.6】整數區間
【題目考點】
1. 貪心
2. 貪心選擇性質的證明
要想證明貪心選擇可以得到最優解,只需要證明最優解包含每一次的貪心選擇。
使用數學歸納法:
【解題思路】
每次選擇右端最小的區間的右端數字,并刪掉所有包含該數字的區間。
用數學語言說,現有區間:e1=[l1,r1],e2=[l2,r2],...,en=[ln,rn]e_1=[l_1,r_1], e_2=[l_2,r_2],...,e_n=[l_n,r_n]e1?=[l1?,r1?],e2?=[l2?,r2?],...,en?=[ln?,rn?]
選擇右端點r最小的區間em=[lm,rm]e_m=[l_m,r_m]em?=[lm?,rm?],刪掉所有滿足rm∈exr_m\in e_xrm?∈ex?的區間exe_xex?
1. 貪心選擇性質的證明:
貪心選擇:每次選擇右端最小的區間的右端點數字
記右端最小的區間為em=[lm,rm]e_m = [l_m,r_m]em?=[lm?,rm?],證明存在最優解包含rmr_mrm?
使用反證法:假設所有最優解都不包含rmr_mrm?
對于某一最優解,根據題意:“對于每一個區間,都至少有一個整數屬于該集合”,所以一定要在區間eme_mem?中選擇一個數字。假設該最優解中選擇了區間eme_mem?中的數字xxx且x≠rmx \neq r_mx?=rm?,包含x的區間有p個,組成的集合為:Ex={ex1,ex2,...,exp}E_x = \{e_{x1},e_{x2},...,e_{xp}\}Ex?={ex1?,ex2?,...,exp?},選擇x后,這些區間都被刪掉,不再被考慮。
現在考慮在該最優解中用rmr_mrm?替換xxx,包含rmr_mrm?的區間有q個,組成集合為:Er={er1,er2,...,erq}E_r=\{e_{r1},e_{r2},...,e_{rq}\}Er?={er1?,er2?,...,erq?},由于eme_mem?是右端最小的區間,所以ExE_xEx?中的所有區間的右端都大于等于rmr_mrm?,也就是說rmr_mrm?在ExE_xEx?的每個區間中,亦即Ex?ErE_x\subseteq E_rEx??Er?。選擇rmr_mrm?后,ErE_rEr?中的所有區間都被刪除,包括了ExE_xEx?中的所有區間。該最優解中其他數字不變,仍然可以形成一組最優解。而這組最優解包含了rmr_mrm?,與假設相悖。因而原命題得證。
證明方法與證明第1點相似,不再贅述。
2. 具體做法
將所有區間排序,排序規則為:右端小的排在前面;如果右端相同,那么左端小的排在前面。
按順序遍歷各個區間,選擇當前區間的右端點并記錄,選擇的數字個數加1。
繼續遍歷,如果當前區間的左端點小于等于之前記錄的右端點,那么略過這個區間。
如果當前區間左端點大于之前記錄的右端點,那么選擇當前區間的右端點并記錄,選擇的數字個數加1。
重復上述過程,直至遍歷完所有區間。
【題解代碼】
解法1:貪心
#include<bits/stdc++.h> using namespace std; struct Sec {int l, r;//l:區間左端點 r:區間右端點 }; bool cmp(const Sec &a, const Sec &b) {//右端點更小的排在前面,右端點相同則左端點更小的在前面 if(a.r == b.r)return a.l < b.l;elsereturn a.r < b.r; } int main() {Sec s[10005];int n, ct = 0, lastR = -1;//lastR:上一個選擇的右端點 ct:選擇的數字個數cin >> n;for(int i = 1; i <= n; ++i)cin >> s[i].l >> s[i].r;sort(s+1, s+1+n, cmp);for(int i = 1; i <= n; ++i){if(s[i].l > lastR){ct++;lastR = s[i].r; }}cout << ct;return 0; }總結
以上是生活随笔為你收集整理的信息学奥赛一本通 1324:【例6.6】整数区间的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql_query mysqli_q
- 下一篇: mysql 中average_mysql