区间问题
区间选点
思路
区间问题,可以先将区间进行排序,假设以区间右端点进行排序
接着依次遍历每一个区间,
- 如果当前区间已经包含点,跳过这一步
ed > range[i].l
- 否则,选择当前区间的右端点
ed < range[i].l, res++, ed=range[i].r
代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
struct Range
{
int l, r;
bool operator< (const Range &w)const
{
return r < w.r;
}
} range[N];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
int l, r;
cin >> l >> r;
range[i] = {l, r};
}
// 初始化
int res = 0, ed = -2e9;
sort(range, range + n);
for (int i = 0; i < n; i++)
{
if (range[i].l > ed)
{
res++;
ed = range[i].r;
}
}
cout << res << endl;
return 0;
}
最大不相交区间数量
思路:
本题与上题思路类似,区间选点,要求选择特定的点覆盖所有区间,不同点分属于不相交的区间,因此可以用区间选点的方式进行求解。
代码:
以左端点排序
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
struct Range
{
int l, r;
bool operator< (const Range &w)const
{
return l < w.l;
}
} range[N];
int main()
{
int 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 = 1, ed = range[0].r;
for (int i = 0; i < n; i++)
{
if (range[i].l > ed)
{
res++;
ed = range[i].r;
}
else ed = min(ed, range[i].r);
}
cout << res << endl;
return 0;
}
以右端点排序
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
struct Range
{
int l, r;
bool operator< (const Range &w)const
{
return r < w.r;
}
} range[N];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
int l, r;
cin >> l >> r;
range[i] = {l, r};
}
int res = 0, ed = -2e9;
sort(range, range + n);
for (int i = 0; i < n; i++)
{
if (range[i].l > ed)
{
res++;
ed = range[i].r;
}
}
cout << res << endl;
return 0;
}
区间分组
思路:
区间问题,按照左端点进行排序。用一个小根堆维护每一个分组中最大的右端点。
如果堆空,或者当前区间的左端点小于分组区间右端点的最小值,如上图1,则开辟一个新区间,也就是上该区间的右端点入堆。否则,更新右端点,如图2.
代码
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010;
struct Range
{
int l, r;
bool operator< (const Range &w)const
{
return l < w.l;
}
}range[N];
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
int l, r;
scanf("%d%d", &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++)
{
// 如果堆空,或者当前区间左端点小于分组区间右端点的最小值,有冲突,则再开辟一个分组
if (heap.empty() || heap.top() >= range[i].l) heap.push(range[i].r);
// 如果不冲突,则更新当前组右端点
else
{
heap.pop();
heap.push(range[i].r);
}
}
printf("%d", heap.size());
return 0;
}
Huffman树
合并果子
思路:
很容易想到哈夫曼树,每次选择两个最小数目相加,得一个新的数目,可以用小根堆来维护。
代码:
#include <iostream>
#include <queue>
using namespace std;
int main()
{
int n;
cin >> n;
priority_queue<int, vector<int>, greater<int> > heap;
while (n--)
{
int x;
cin >> x;
heap.push(x);
}
int res = 0;
while (heap.size() > 1)
{
int a = heap.top();
heap.pop();
int b = heap.top();
heap.pop();
res += a + b;
heap.push(a + b);
}
cout << res << endl;
return 0;
}