3個典型區間貪心問題(總結篇)
阿新 • • 發佈:2019-01-27
1.數軸上有n個閉區間[ai,bi]。取儘量少的點,使得每個區間內都至少有一個點(不同區間內含的點可以是同一個)。
2.數軸上有n個開區間(ai,bi)。最多能有多少個互不相交的區間?
3.數軸上有n個區間[ai,bi],選擇儘量少的區間覆蓋一條指定線段[s,t]。
解法:
1.
貪心策略:
按照b1<=b2<=b3…(b相同時按a從大到小)的方式排序排序,從前向後遍歷,當遇到沒有加入集合的區間時,選取這個區間的右端點b。
程式碼:
2.#include<cstdio> #include<algorithm> #include<vector> #include<cstring> using namespace std; typedef struct node { int l,r; }node; node p[100005]; bool cmp(node a,node b){ return a.r<b.r; } int main() { int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d%d",&p[i].l,&p[i].r); sort(p,p+n,cmp); int now=-1; int ans=0; for(int i=0;i<n;i++){ if(p[i].l>now){ now=p[i].r; ans++; } } printf("%d\n",ans); } return 0; }
貪心策略:
按照b1<=b2<=b3…的方式排序,然後從前向後遍歷,每當遇到可以加入集合的區間,就把它加入集合。(集合代表解的集合)
程式碼:
3.#include <stdio.h> #include <algorithm> using namespace std; struct Extent { int a,b; bool operator < (const Extent& S)const { return b < S.b; } }A[10002]; int main() { int z,n,cnt,end; scanf("%d",&z); while(z--) { cnt = 0; end = -1; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d%d",&A[i].a,&A[i].b); sort(A,A+n); for(int i=0;i<n;i++) { if(end < A[i].a) { end = A[i].b; cnt++; } } printf("%d\n",cnt); } return 0; }
貪心策略:
把各區間按照a從小到大排序,從前向後遍歷,然後每次選擇從當前起點S開始的最長區間,並以這個區間的右端點為新的起點,繼續選擇,直到找不到區間覆蓋當前起點S或者S已經到達線段末端。
需要注意的是,如果某一區間邊界大於s,t的邊界,應把它們變成s或t。因為超出的部分毫無意義,同時還會影響對資料的分析。
程式碼:
部分參考:http://blog.csdn.net/dgq8211/article/details/7535994#include <math.h> #include <stdio.h> #include <algorithm> using namespace std; struct Qujian { float a,b; }; bool cmp(const Qujian& s1,const Qujian& s2) { return s1.a < s2.a; } int main() { Qujian A[10005]; int z,n,w,h,x,r,cnt; float start,l,__h; scanf("%d",&z); while(z--) { scanf("%d%d%d",&n,&w,&h); cnt = start = 0; __h = h*h*1.0/4; for(int i=0;i<n;i++) { scanf("%d%d",&x,&r); if(r*r < __h) { i--;n--; continue; } l = sqrt(r*r - __h); A[i].a = x-l > 0 ? x-l : 0; A[i].b = x+l < w ? x+l : w; } sort(A,A+n,cmp); int i,k = -1; while(start < w && A[k+1].a <= start) { float mmax = -1; for(i = k+1;A[i].a <= start && i<n;i++) if(mmax < A[i].b) { mmax = A[i].b; k = i; } start = mmax; cnt++; } printf("%d\n",start<w ? 0 : cnt); } return 0; }