三類基于貪心思想的區間覆蓋問題

一、區間完全覆蓋問題

問題描述:給定一個長度為m的區間,再給出n條線段的起點和終點(注意這里是閉區間),求最少使用多少條線段可以將整個區間完全覆蓋。

樣例:一個長度為8的區間,可選的線段有[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5]。

求解過程:

1、將每一條線段按左端點遞增順序排列,如果左端點相同,按右端點遞增順序排列,排完序后為[1,4],[2,4],[2,6],[3,5],[3,6],[3,7],[6,8];

2、設置一個變量表示已覆蓋到的區間右端點,在剩下的線段中找出所有左端點小于等于當前已覆蓋到的區間右端點的線段,選擇右端點最大并且大于當前已覆蓋到的區間右端點,重復以上操作直至覆蓋整個區間;

3、模擬過程:假設第一次加入[1,4],那么下一次能夠選擇的線段有[2,6],[3,5],[3,6],[3,7],由于3小于4且7最大,所以下一次選擇[3,7]進行覆蓋,最后一次只能選擇[6,8],這個時候剛好覆蓋長為8的區間-->break;即所選3條線段就能覆蓋長度為8的大區間;

4、貪心證明:

要求用最少的線段進行覆蓋,那么選取的線段必然要盡量長,而已覆蓋到的區域之前的地方已經不用考慮了,可以理解成所有可覆蓋的左端點都已被覆蓋了,那么能夠使得線段更長的取決于右端點,左端點沒有太大的意義,所以選擇右端點來覆蓋。

題解報告:NYOJ #12?噴水裝置(二)

描述

有一塊草坪,橫向長w,縱向長為h,在它的橫向中心線上不同位置處裝有n(n<=10000)個點狀的噴水裝置,每個噴水裝置i噴水的效果是讓以它為中心半徑為Ri的圓都被潤濕。請在給出的噴水裝置中選擇盡量少的噴水裝置,把整個草坪全部潤濕。

輸入

第一行輸入一個正整數N表示共有n次測試數據。每一組測試數據的第一行有三個整數n,w,h,n表示共有n個噴水裝置,w表示草坪的橫向長度,h表示草坪的縱向長度。隨后的n行,都有兩個整數xi和ri,xi表示第i個噴水裝置的的橫坐標(最左邊為0),ri表示該噴水裝置能覆蓋的圓的半徑。

輸出

每組測試數據輸出一個正整數,表示共需要多少個噴水裝置,每個輸出單獨占一行。如果不存在一種能夠把整個草坪濕潤的方案,請輸出0。

樣例輸入

2
2 8 6
1 1
4 5
2 10 6
4 5
6 5

樣例輸出

1
2
解題思路:典型的區間完全覆蓋問題。由于噴水裝置是安置在橫向中心線上并且圓具有對稱性,故只需取高度的一半,然后將每個噴水裝置能夠覆蓋的區間范圍映射成在x軸的長度,然后按上面的方法貪心選線段即可。
AC代碼:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=10005;
 4 int t,n,k,cnt,pos,beg;double w,h,lb,xi,ri,maxv;pair<double,double> itv[maxn];bool flag;
 5 int main(){
 6     while(cin>>t){
 7         while(t--){
 8             cin>>n>>w>>h;h/=2.0;pos=cnt=0;//h取一半
 9             for(int i=0;i<n;++i){
10                 cin>>xi>>ri;
11                 if(ri<h)continue;//ri==h也要算
12                 itv[pos].first=xi-sqrt(ri*ri-h*h);
13                 itv[pos++].second=xi+sqrt(ri*ri-h*h);
14             }
15             sort(itv,itv+pos);lb=0;beg=0;flag=false;
16             if(itv[0].first>0){cout<<0<<endl;continue;}//按左端點排序只需查看最左邊的端點是否滿足條件即可,最右邊的端點在下面有判斷
17             while(lb<w){
18                 maxv=0;
19                 for(k=beg;k<pos&&itv[k].first<=lb;++k)//itv[k].first<=lb這樣保證整個區間是連續的,即草坪都會被潤濕
20                     maxv=max(maxv,itv[k].second);//找線段左端點在lb以內右端點能覆蓋到的最遠距離
21                 if(maxv>lb)cnt++,lb=maxv,beg=k;//如果有一條線段右端點比當前已覆蓋的區間右端點lb還大,那么就更新已覆蓋的右端點值,同時計數器加1
22                 else {flag=true;break;}//否則說明不能覆蓋整個區間,直接退出,輸出0
23             }
24             if(flag)cout<<0<<endl;
25             else cout<<cnt<<endl;
26         }
27     }
28     return 0;
29 }

題解報告:NYOJ #6?噴水裝置(一)

描述

現有一塊草坪,長為20米,寬為2米,要在橫中心線上放置半徑為Ri的噴水裝置,每個噴水裝置的效果都會讓以它為中心的半徑為實數Ri(0<Ri<15)的圓被濕潤,這有充足的噴水裝置i(1<i<600)個,并且一定能把草坪全部濕潤,你要做的是:選擇盡量少的噴水裝置,把整個草坪的全部濕潤。

輸入

第一行m表示有m組測試數據;每一組測試數據的第一行有一個整數數n,n表示共有n個噴水裝置,隨后的一行,有n個實數ri,ri表示該噴水裝置能覆蓋的圓的半徑。

輸出

輸出所用裝置的個數

樣例輸入

2
5
2 3.2 4 4.5 6 
10
1 2 3 1 2 1.2 3 1.1 1 2

樣例輸出

2
5
解題思路:將每個能噴灑到草坪邊緣的噴水裝置的噴灑范圍映射成在x軸的長度,然后按線段長度遞增順序排列,再從后往前貪心選線段即可得到選擇最少的噴水裝置來潤濕整個草坪。AC代碼:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int t,n,cnt;double ans,ri,dt[605];
 4 int main(){
 5     while(cin>>t){
 6         while(t--){
 7             cin>>n;ans=0;cnt=0;
 8             for(int i=0;i<n;++i)cin>>ri,dt[i]=ri>1?sqrt(ri*ri-1):0;//這里可以設置為0,因為題目已經保證一定可以將草坪全部潤濕
 9             sort(dt,dt+n);
10             for(int i=n-1;ans<=10.0&&i>=0;--i)cnt++,ans+=dt[i];//從后往前能選出最少數量的噴水裝置,且一定能將草坪潤濕
11             cout<<cnt<<endl;
12         }
13     }
14     return 0;
15 }

?二、最大不相交區間數問題

問題描述:數軸上有n個區間$ [a_i,b_i] $,要求選擇盡量多個區間,使得這些區間兩兩沒有公共點。

樣例:數軸上有7個區間,可選的區間有[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5]。

求解過程:

1、按區間右端點遞增順序排列,如果右端點相同,按左端點遞增順序排序,排完序后為[1,4],[2,4],[3,5],[2,6],[3,6],[3,7],[6,8];
2、第一次選擇[1,4],接下來只能選擇[6,8],即當前數軸上最多只能選擇兩個不相交的區間。

3、貪心證明:為了選擇更多的區間個數,先按區間右端點遞增順序排列,然后順序處理每個區間,如果它與當前已選的所有區間都沒有相交,則選擇該區間,否則不選。接下來證明區間左端點a1,a2…對右端點沒有影響:

①當a1>a2時,區間2包含區間1,顯然不能選擇區間2,因為選擇區間1會留下更多的區域。不僅區間2如此,以后所有區間中只要有一個i滿足a1>ai,i都不要選,所以此種情況下,選擇區間1是明智的,與策略一致。

②排除情況1后,一定有a1<=a2<=a3……,此時選擇區間1是最優策略,說明無論左端點是大是小,只要對區間右端點進行排序,然后貪心選擇不相交的區間就可得到數軸上最多不相交的區間個數,即這個策略是正確的。

?

題解報告:NYOJ #14?會場安排問題

描述

學校的小禮堂每天都會有許多活動,有時間這些活動的計劃時間會發生沖突,需要選擇出一些活動進行舉辦。小劉的工作就是安排學校小禮堂的活動,每個時間最多安排一個活動。現在小劉有一些活動計劃的時間表,他想盡可能的安排更多的活動,請問他該如何安排。

輸入

第一行是一個整型數m(m<100)表示共有m組測試數據。
每組測試數據的第一行是一個整數n(1<n<10000)表示該測試數據共有n個活動。
隨后的n行,每行有兩個正整數Bi,Ei(0<=Bi,Ei<10000),分別表示第i個活動的起始與結束時間(Bi<=Ei)

輸出

對于每一組輸入,輸出最多能夠安排的活動數量。
每組的輸出占一行

樣例輸入

2
2
1 10
10 11
3
1 10
10 11
11 20

樣例輸出

1
2
解題思路:按結束時間早進行排序,然后貪心選擇不相交區間即可。
AC代碼:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=10005;
 5 int t,n,tmp,ans;pair<int,int> itv[maxn];
 6 int main(){
 7     while(cin>>t){
 8         while(t--){
 9             cin>>n;
10             for(int i=0;i<n;++i)cin>>itv[i].second>>itv[i].first;
11             sort(itv,itv+n);tmp=-1;ans=0;//按結束時間早進行排序
12             for(int i=0;i<n;++i)
13                 if(tmp<itv[i].second)ans++,tmp=itv[i].first;
14             cout<<ans<<endl;
15         }
16     }
17     return 0;
18 }

三、區間選點問題

問題描述:數軸上有n個閉區間 $[a_i,b_i] $,要求選取盡量少的點,使得每個區間內都至少有一個點(不同區間內含的點可以是同一個)。

樣例略。

求解過程:

1、按左端點遞增順序排序,如果左端點相同,按右端點遞增順序排序,個人覺得這種比較好理解,當然也可以按右端點遞增順序排序。

2、①從第一個區間右端點開始貪心往后找,如果下一個區間的左端點大于當前已選區間的右端點,說明要新開一個點,計數器加1,同時更新右區間能覆蓋的最遠距離;②如果下一個區間右端點小于當前已選區間的右端點,說明共享的線段范圍縮短了,那么就更新區間右端點為下一個區間右端點,重復以上操作,直至篩選完所有區間。

貪心證明:為了選擇最少的點使得每個區間內至少含有一個點,考慮按區間左端點遞增順序排序,如果左端點相同,則按區間右端點遞增順序排序,然后以第一個區間右端點作為第一個點能覆蓋的最大范圍。①當b1>b2時,顯然此時一個點能覆蓋最大的區域右邊界變為b2,同理,以后只要滿足 $ b_1 > b_i $,一個點能覆蓋的區域右邊界就會變為 $ b_i $,顯然這是正確的;②當b1<a2時,顯然一個點不能覆蓋到區間2上,所以需新開一個點,此時能覆蓋的區域最右邊界變為b2,同理,以后只要滿足 $ b1 < a_i $,則都要新開一個點,并且其能覆蓋的區域右邊界將變為 $ b_i $,顯然這也是正確的;③?當b1<b2時,顯然區間1和區間2有公共的部分,但此時一個點能覆蓋的區域最右邊界還是為 b1,無需更新區域最右邊界,同理,對于以后只要滿足 $ b_1<b_i $,都無需新開一個點,也無需更新能覆蓋區域的最右邊界,顯然這也是正確的。綜上,按區間左端點遞增的順序排序,再按規則貪心選點的策略是正確的。

題解報告:NYOJ #891 找點

描述

上數學課時,老師給了LYH一些閉區間,讓他取盡量少的點,使得每個閉區間內至少有一個點。但是這幾天LYH太忙了,你們幫幫他嗎?

輸入

多組測試數據。
每組數據先輸入一個N,表示有N個閉區間(N≤100)。
接下來N行,每行輸入兩個數a,b(0≤a≤b≤100),表示區間的兩個端點。

輸出

輸出一個整數,表示最少需要找幾個點。

樣例輸入

4
1 5
2 4
1 4
2 3
3
1 2
3 4
5 6
1
2 2

樣例輸出

1
3
1
解題思路:按左端點遞增順序排序,然后按上面的求解方法貪心選點即可。
AC代碼:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=105;
 5 int n,tmp,ans;pair<int,int> itv[maxn];
 6 int main(){
 7     while(cin>>n){
 8         for(int i=0;i<n;++i)cin>>itv[i].first>>itv[i].second;
 9         sort(itv,itv+n);tmp=itv[0].second;ans=1;
10         for(int i=0;i<n;++i){
11             if(tmp<itv[i].first)ans++,tmp=itv[i].second;
12             else if(tmp>itv[i].second)tmp=itv[i].second;
13         }
14         cout<<ans<<endl;
15     }
16     return 0;
17 }

題解報告:poj 1328?Radar Installation

Description

Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d.?
We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.?
?
Figure A Sample Input of Radar Installations

Input

The input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases.?
The input is terminated by a line containing pair of zeros?

Output

For each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. "-1" installation means no solution for that case.

Sample Input

3 2
1 2
-3 1
2 11 2
0 20 0

Sample Output

Case 1: 2
Case 2: 1
解題思路:典型的區間選點,將雷達能覆蓋的范圍映射為x軸上的線段長度,然后貪心區間選點即可。
AC代碼:
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cmath>
 4 using namespace std;
 5 const int maxn=1005;
 6 int n,d,ans,pos,cnt=1,x,y;double tmp;
 7 struct node{double l,r;}point[maxn];
 8 bool cmp(node a,node b){return a.l<b.l;}
 9 int main(){
10     while(cin>>n>>d&&(n|d)){//注意這里:n|d,表示n和d同時為0時,程序才退出
11         ans=1;pos=0;
12         for(int i=0;i<n;++i){
13             cin>>x>>y;
14             if(y>d){ans=-1;continue;}//根號下只能為非負數
15             point[pos].l=1.0*x-sqrt(1.0*d*d-y*y);//以每個島嶼為圓心,半徑為d畫圓,其與x軸最后只有兩個交點
16             point[pos++].r=1.0*x+sqrt(1.0*d*d-y*y);
17         }
18         sort(point,point+pos,cmp);tmp=point[0].r;
19         for(int i=1;i<pos&&ans!=-1;++i){
20             if(tmp<point[i].l){ans++;tmp=point[i].r;}//如果已選線段與當前線段不相交,那么就設置一個新的雷達,然后更新tmp為其右端點值
21             else if(tmp>point[i].r)tmp=point[i].r;//可以覆蓋掉下一條線段,但此時區間右端點縮短為下一條線段的右端點,說明覆蓋的范圍縮短了
22         }
23         cout<<"Case "<<cnt++<<": "<<ans<<endl;
24     }
25     return 0;
26 }

?

轉載于:https://www.cnblogs.com/acgoto/p/9824723.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/450956.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/450956.shtml
英文地址,請注明出處:http://en.pswp.cn/news/450956.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ubuntu 常用軟件和命令

永久修改屏幕的分辨率   sudo gedit .profile 將下面的四句話加入。.profile文件的最后   cvt 1280 768   xrandr --newmode "1280x768_60.00" 79.50 1280 1344 1472 1664 768 771 781 798 -hsync vsync   xrandr --addmode Virtual1 "1280x768_60.00&q…

Eclipse搭建Android開發環境(安裝ADT,Android4.4.2)

見&#xff1a;http://blog.csdn.net/zht666/article/details/29837777 使用Eclipse做Android開發&#xff0c;需要先在Eclipse上安裝ADT&#xff08;Android Development Tools&#xff09;插件。 1.安裝JDK 1.7 JDK官網http://www.oracle.com/technetwork/java/javase/downlo…

C語言 位操作簡析

位運算 前面介紹的各種運算都是以字節作為最基本位進行的。 但在很多系統程序中常要求在位(bit)一級進行運算或處理。&#xff23;語言提供了位運算的功能&#xff0c; 這使得&#xff23;語言也能像匯編語言一樣用來編寫系統程序。 一、位運算符&#xff23;語言提供了六種位運…

算法:輸入一個鏈表,輸出該鏈表中倒數第k個結點。

算法&#xff1a;輸入一個鏈表&#xff0c;輸出該鏈表中倒數第k個結點。《劍指offer》 思路加到注釋里面了&#xff1b; 1&#xff1a;兩個if判斷是否返回值為空&#xff0c;首個為空&#xff0c;沒有第k個值&#xff1b; 2&#xff1a;for循環找到倒數第k個值&#xff0c;返回…

Spring事務那些事兒

&#xff08;一&#xff09;事務的隔離級別 大家都知道事務有四個屬性&#xff0c;即ACID&#xff08;原子性、一致性、隔離性、持久性&#xff09;。這四個里面稍微難理解點的是一致性和持久性。所謂的一致性是指&#xff1a;事務執行前后數據的一致性狀態&#xff0c;例如事…

Silverlight Blend動畫設計系列八:拖放(Drag-Drop)操作與拖放行為(DragBehavior)

Silverlight & Blend動畫設計系列八&#xff1a;拖放(Drag-Drop)操作與拖放行為(DragBehavior) 原文:Silverlight & Blend動畫設計系列八&#xff1a;拖放(Drag-Drop)操作與拖放行為(DragBehavior)在Silverlight中自身并沒有提供拖放功能的相關實現&#xff0c;要實現拖…

mysql查詢顯示行號

見&#xff1a;http://blog.csdn.net/muzizhuben/article/details/49449853 使用mysql查詢顯示行號&#xff0c;沒有像oracle這么方便。 不過也可以通過設定變量顯示行號&#xff0c;例如&#xff1a; -- 生成 行號 select r:r1 as rowno , a.* from my_tb a ,(select r:0) b …

scanf 用法大全

關于標準庫函數scanf論壇上很多人對scanf的不太了解&#xff0c;導致程序出錯&#xff0c;我想把scanf的具體用法貼出來&#xff0c;希望大家可以共同進步&#xff0c;有什么不對的地方可以提出來。int scanf(char *format&#xff0c;...);這應該是scanf的標準形式。先說說關于…

深入了解Spring IoC

IoC全稱Inversion of Control即控制反轉&#xff0c;它還有一個別名依賴注入。spring利用Ioc容器幫我們自動構建對象及注入依賴對象&#xff0c;減少了對象構建與業務代碼的耦合&#xff0c;使得我們能夠更加高效愉快的寫bug&#x1f41e;了(&#xffe3;▽&#xffe3;)"…

軟文營銷實戰記錄

最近拜讀了徐茂權老師的《 網絡營銷決勝武器(第2版)》&#xff0c;下面會梳理書中的內容&#xff0c;記錄下以后可能會用到的軟文營銷的技巧。 一、軟文載體 1、平面媒體軟文&#xff1a;報紙、期刊。 2、非正式出版的基于印刷、打印形式載體的軟文&#xff1a;企業印刷的宣傳冊…

oracle中rownum和row_number()的區別

見&#xff1a;http://www.jb51.net/article/65960.htm row_number()over(partition by col1 order by col2)表示根據col1分組&#xff0c;在分組內部根據col2排序&#xff0c;而此函數計算的值就表示每組內部排序后的順序編號&#xff08;組內連續的唯一的&#xff09;。 與ro…

java類加載順序

在java中類的加載、初始化都是在程序運行期完成的&#xff0c;雖然會稍微增加開銷&#xff0c;但是卻很大的增加了靈活性&#xff0c;我們可用在運行期間動態的去網絡或其他地方加載一個二進制流來作為程序代碼的一部分。接下來我們簡單介紹下java類加載過程。 從上圖中我們可…

dealloc不調用的情況

2019獨角獸企業重金招聘Python工程師標準>>> 1、沒有停止定時器 - (void)dealloc { [_timer invalidate]; _timer nil; } 2、VC中有代理Delegate&#xff0c;需要設置delegate的時候&#xff0c;設置為weak property (nonatomic,weak) id<ZoeEatDe…

day10-列表生成式

列表生成式即List Comprehensions&#xff0c;是Python內置的非常簡單卻強大的可以用來創建list的生成式。 1、生成一個列表 a [i for i in range(1,100) if i%21]print(list(a))或print(a)[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, …

jrebel、JavaRebel

見&#xff1a;https://baike.baidu.com/item/jrebel/1115725?fraladdin JRebel是一套JavaEE開發工具。中文名jrebel屬 性JavaEE開發工具資 費收費軟件作 用Jrebel 可快速實現熱部署JRebel是一套JavaEE開發工具。JRebel允許開發團隊在有限的時間內完成更多的任務修正…

自己寫函數庫

大家現在寫 程序&#xff0c;是不是都是用新唐提供的函數庫&#xff1f;在體驗 開發板的一開始&#xff0c;我也是使用函數庫&#xff0c;畢竟這個太方便了。可是有一天&#xff0c;我發現一個只使用時鐘和IO以及 調試 串口的程序居然查過了16k的時候&#xff0c;我震驚了&…

[MicroPython]stm32f407控制DS18B20檢測溫度

2019獨角獸企業重金招聘Python工程師標準>>> 1.實驗目的 1. 學習在PC機系統中擴展簡單I/O 接口的方法。 2. 進一步學習編制數據輸出程序的設計方法。 3. 學習DS18B20的接線方法&#xff0c;并利用DS18B20檢測當前溫度。 2.所需元器件 F407Micropython開發板…

帶你理解Spring AOP

AOP概述 在我們的日常開發中&#xff0c;除了正常業務邏輯外&#xff0c;還可能經常會需要在業務邏輯的特定位置加入日志&#xff0c;以便于調試和問題分析。但是這種插入日志的邏輯和業務邏輯間并不存在連續性和依賴性&#xff0c;這種邏輯侵入隨著項目的不斷發展&#xff0c…

10.20隨筆

ES6 ECMAScript是一種由Ecma國際&#xff08;前身為歐洲計算機制造商協會,英文名稱是European Computer Manufacturers Association&#xff09;通過ECMA-262標準化的腳本程序設計語言。 這種語言在萬維網上應用廣泛&#xff0c;它往往被稱為JavaScript或JScript&#xff0c;但…

極客招募令!兄弟杯區塊鏈極客競技大賽在上海等您來戰!

據悉&#xff0c;由國內首家區塊鏈技術社區區塊鏈兄弟主辦&#xff0c;旺鏈科技、離子鏈、中國云體系產業創新戰略聯盟、無退社區、指旺金科等單位強力支持&#xff0c;HiBlock區塊鏈社區、火球財經、布洛克財經、海豚區塊鏈、區塊網等百家技術社區和媒體通力合作的兄弟杯區塊鏈…