貪心-區間覆蓋
給定N個閉區間[ai,biai,bi]以及一個線段區間[s,ts,t],請你選擇儘量少的區間,將指定線段區間完全覆蓋。
輸出最少區間數,如果無法完全覆蓋則輸出-1。
輸入格式
第一行包含兩個整數s和t,表示給定線段區間的兩個端點。
第二行包含整數N,表示給定區間數。
接下來N行,每行包含兩個整數ai,biai,bi,表示一個區間的兩個端點。
輸出格式
輸出一個整數,表示所需最少區間數。
如果無解,則輸出-1。
數據範圍
1≤N≤1051≤N≤105,
−109≤ai≤bi≤109−109≤ai≤bi≤109,
−109≤s≤t≤109−109≤s≤t≤109
輸入樣例:
1 5
3
-1 3
2 4
3 5
輸出樣例:
2
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
struct Range
{
int l, r;
bool operator< (const Range &w)const
{
return l < w.l;
}
}range[N];
int main()
{
int st, ed;
cin >> st >> ed >> n;
//cin >> n;
for (int i = 0; i < n; i ++)
{
int l, r;
cin >> l >> r;
range[i] = {l, r};
}
sort(range, range + n);
int res = 0;
bool success = false;
for (int i = 0; i < n; i ++)
{
int j = i, r = -2e9;
while (j < n && range[j].l <= st)//找到一個能覆蓋st並且右端點最長的值
{
r = max(r, range[j].r);
j ++;
}
if (r < st)//如果最後找到的值沒有能覆蓋st的就break,如果沒有這一步,遇到全部都是大於st的區間就會TLE
{
res = -1;
break;
}
res ++;
if (r >= ed)//如果st已經大於ed了就break
{
success = true;
break;
}
st = r;//更新st
i = j - 1;
}
if (!success) res = -1;//判斷一下最後覆蓋到的區間是否已經過了ed
cout << res << endl;
return 0;
}
貪心-區間分組
給定N個閉區間[ai,bi],請你將這些區間分成若干組,使得每組內部的區間兩兩之間(包括端點)沒有交集,並使得組數儘可能小。
輸出最小組數。
輸入格式
第一行包含整數N,表示區間數。
接下來N行,每行包含兩個整數ai,biai,bi,表示一個區間的兩個端點。
輸出格式
輸出一個整數,表示最小組數。
數據範圍
1≤N≤1051≤N≤105,
−109≤ai≤bi≤109−109≤ai≤bi≤109
輸入樣例:
3
-1 1
2 4
3 5
輸出樣例:
2
分情況討論貪心決策:
1.如果一個區間的左端點比當前每一個組的最右端點都要小,那麼意味着要開一個新區間了,這個條件還可以優化成,一個區間左端點比最小組的右端點都要小就開一個新組。
2.如果一個區間的左端點比最小組的右端點大,那麼就放在該組,這其實也是一個貪心,因爲是先考慮最容易放入一個區間的組
這道題對於數據結構上的選擇也要考慮,用一個小頂堆,也就是優先隊列來存儲每一個組的最右端點是最好的數據結構了。
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010;
int n;
struct Range
{
int l, r;
//< 排序
bool operator< (const Range &w)const
{
return l < w.l;
}
}range[N];
int main()
{
//輸入
cin >> n;
for (int i = 0; i < n; i ++)
{
int l, r;
cin >> l >> r;
range[i] = {l, r};
}
//排序
sort(range, range + n);
//定義小根堆,定義語法如下
//來維護所有組的最大值
priority_queue<int, vector<int>, greater<int>> heap;
for (int i = 0; i < n; i ++)
{
//用r來代表區間
auto r = range[i];
//如果堆爲空或者堆頂最小值>=i區間左端點,區間需要開一個新的組
if (heap.empty() || heap.top() >= r.l) heap.push(r.r);
else
{//否則這個區間放在最小值組中
int t = heap.top();
heap.pop();//出堆,把最小值堆頂刪掉刪掉
heap.push(r.r);//加入新的右端點放進去
}
}
cout << heap.size() << endl;//最後輸出組的數量
return 0;
}
貪心-最大不相交區間數量
給定N個閉區間[ai,biai,bi],請你在數軸上選擇若干區間,使得選中的區間之間互不相交(包括端點)。
輸出可選取區間的最大數量。
輸入格式
第一行包含整數N,表示區間數。
接下來N行,每行包含兩個整數ai,biai,bi,表示一個區間的兩個端點。
輸出格式
輸出一個整數,表示可選取區間的最大數量。
數據範圍
1≤N≤1051≤N≤105,
−109≤ai≤bi≤109−109≤ai≤bi≤109
輸入樣例:
3
-1 1
2 4
3 5
輸出樣例:
2
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
//結構體排序
struct Range
{
int l, r;
bool operator< (const Range &w)const
{
return r < w.r;
}
}range[N];
int main()
{
cin >> n;
for (int i = 0; i < n; i ++)
{
int l, r;
cin >> l >> r;
range[i] = {l, r};
}
sort(range, range + n);
int res = 0, ed = -2e9;
//枚舉每個區間
for (int i = 0; i < n; i ++)
if (range[i].l > ed)
{
res ++;
ed = range[i].r;
}
cout << res << endl;
return 0;
}
貪心-區間選點
給定N個閉區間[ai,biai,bi],請你在數軸上選擇儘量少的點,使得每個區間內至少包含一個選出的點。
輸出選擇的點的最小數量。
位於區間端點上的點也算作區間內。
輸入格式
第一行包含整數N,表示區間數。
接下來N行,每行包含兩個整數ai,biai,bi,表示一個區間的兩個端點。
輸出格式
輸出一個整數,表示所需的點的最小數量。
數據範圍
1≤N≤1051≤N≤105,
−109≤ai≤bi≤109−109≤ai≤bi≤109
輸入樣例:
3
-1 1
2 4
3 5
輸出樣例:
2
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
//結構體排序
struct Range
{
int l, r;
bool operator< (const Range &w)const
{
return r < w.r;
}
}range[N];
int main()
{
cin >> n;
for (int i = 0; i < n; i ++)
{
int l, r;
cin >> l >> r;
range[i] = {l, r};
}
sort(range, range + n);
int res = 0, ed = -2e9;
//枚舉每個區間
for (int i = 0; i < n; i ++)
if (range[i].l > ed)
{
res ++;
ed = range[i].r;
}
cout << res << endl;
return 0;
}