【題目描述】
一個整數區間[A,B]
請編程完成以下任務:
1.從文件中讀取區間的個數及其它們的描述;
2.找到滿足下述條件的所含元素個數最少的集合中元素的個數,對於每一個區間,都至少有兩個不同的整數屬於該集合。
【輸入】
首行包括區間的數目n,1<=n<=10000,接下來的n 行,每行包括兩個整數a,b,被一空格隔開,0<=a<=b<=10000,它們是某一個區間的開始值和結束值。
【輸出】
第一行集合元素的個數,對於每一個區間都至少有兩個不同的整數屬於該區間,且集合所包含元素數目最少。
樣例輸入
43
6
2 4
0 2
4 7
樣例輸出
4
這道題的題目說的很迷,說人話就是求一個集合,使每一個區間在這個集合里面都至少有兩個元素,輸出集合元素。
一種 O(n ^ 2) 的算法是先開一個標記數組,記錄集合的元素取了哪些。然后按區間開始的端點從小到大排序,從后往前找。開始先標記最后一個區間的前兩個值,然后每一次循環都遍歷該區間的所有數,看看有幾個被放到了集合里。若有兩個,就進行下一次循環;若一個,就標記區間第一個值,ans++;若沒有,就標記區間前兩個值,ans += 2。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 8 #define rep(i ,a, n) for(int i = a; i <= n; ++i) 9 #define per(i, n, a) for(int i = n; i >= a; --i) 10 typedef long long ll; 11 const int maxn = 1e4 + 5; 12 13 struct Node 14 { 15 int sta, end; 16 bool operator < (const Node& other)const 17 { 18 return sta < other.sta; 19 } 20 }a[maxn]; 21 int n; 22 int vis[maxn], sum = 0; 23 int main() 24 { 25 freopen("a.in", "r", stdin); 26 freopen("a.out", "w", stdout); 27 scanf("%d", &n); 28 rep(i, 1, n) scanf("%d%d", &a[i].sta, &a[i].end); 29 sort(a + 1, a + n + 1); 30 per(i, n, 1) 31 { 32 int tot = 0; 33 rep(j, a[i].sta, a[i].end) if(vis[j]) tot++; 34 if(tot == 0) {sum += 2; vis[a[i].sta] = vis[a[i].sta + 1] = 1;} 35 else if(tot == 1) {sum++; vis[a[i].sta] = 1;} 36 } 37 printf("%d\n", sum); 38 return 0; 39 }
這個算法為什么成立呢?因為我們每一次取的都是區間的前兩個值,這樣做就是使所取得這兩個值在接下來的區間中的概率最大,從而在后面的查詢中盡量少的添加集合中的元素。
我們發現,對於每一次區間的操作,只是都用了區間中的前兩個元素。這樣就可以開兩個變量記錄,就不用開數組遍歷了。(默認flag1 < flag2)
若區間末尾大於flag2 ,那么就說明這個區間至少有兩個數被選進集合中了,過;若在flag1 和 flag2 之間,吧 flag1 變成 flag2,flag1 變成 區間開始值;若小於 flag1 ,flag1 和 flag2 分別變成區間頭和頭+1.
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 #define rep(i, a, n) for(int i = a; i <= n; ++i) 8 #define per(i, n, a) for(int i = n; i >= a; --i) 9 typedef long long ll; 10 const int maxn = 1e4 + 5; 11 12 struct Node 13 { 14 int sta, end; 15 bool operator < (const Node& other)const 16 { 17 return sta < other.sta; 18 } 19 }a[maxn]; 20 int n, flag1, flag2; 21 int ans = 0; 22 int main() 23 { 24 freopen("a.in", "r", stdin); 25 freopen("a.out", "w", stdout); 26 scanf("%d", &n); 27 rep(i, 1, n) scanf("%d%d", &a[i].sta, &a[i].end); 28 sort(a + 1, a + n + 1); 29 flag1 = a[n].sta; flag2 = flag1 + 1; ans += 2; 30 per(i, n - 1, 1) 31 { 32 if(a[i].end < flag1) 33 { 34 flag1 = a[i].sta; flag2 = flag1 + 1; 35 ans += 2; 36 } 37 else if(a[i].end >= flag1 && a[i].end < flag2) 38 { 39 flag2 = flag1; flag1 = a[i].sta; 40 ans++; 41 } 42 } 43 printf("%d\n", ans); 44 return 0; 45 }