本题神似区间选点问题,但细细分析后,我们可以发现他们直接的差异处,不过都是利用了对左右端点排序的分析和做出不影响下一个区间选择的贪心策略
有几种贪心的策略,但是不一定正确,首先我们要检验他们的正确性
1.min升序排序,选择满足条件的防晒中spf最小的
2.min降序排序,选择满足条件的防晒中spf最大的
3.max降序排序,选择满足条件的防晒中spf最大的
1.min升序排序,选择满足条件的防晒中spf最小的
min可以称为左端点,max可以称为右端点
我们可以很自然的想到左端点排序,然后选择所有能选择的点中spf最小的,那么这种策略正确吗
首先,选择左端点升序,选择spf最小的防晒,从图中看看似是正确的,自然选择spf最大的是错误的
但是,我们知道左端点排序,下一个区间可能是比完全小的,也就是说,当前区间能够用的防嗮,下一个区间不一定能够使用,如图所示
由于1号区间先被遍历,他先选了左边的防晒,将会导致2号区间原本能选的防晒不能选了,最后满足条件的牛个数只有1,不是最优解,所以可证min升序,选择spf最大的是错误的
2.min降序排序 ,选择满足条件的spf最大的
左端点降序排序的特点是,下一个区间可能是比当前区间完全大的,如图所示,2号区间比1号区间完全大,此时1号区间选择任意一个spf都是可以的,因为能满足1号区间的防晒也一定能满足2号区间。
而3号区间左端点比1号区间小,我们只能选择spf大的
所以我们可以得出结论,对于当前区间min降序排序,优先选择spf大的
同样的max升序和max降序就不用多分析了,因为他们的性质分别对应min降序和min升序
所以最优解是
1.min降序排序,优先选择spf大的
2.max升序排序,优先选择spf小的
这里不能使用双指针算法的原因
下一个区间可能是比当前区间大的,即使我们的spf按照大小排序,可能下一个区间在当前区间的范围内找不到合适的防晒霜,在他之前的区间也可能找到,如图所示,所以应该用二重循环,N^2的时间复杂度
min降序排序
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2505;
struct Cow
{
int min;
int max;
bool operator <(const Cow b)const
{
return min > b.min;
}
}c[N];
struct Fang
{
int spf;
int num;
bool operator < (const Fang b)const
{
return spf > b.spf;
}
}a[N];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 0;i < n;i++)
cin >> c[i].min >> c[i].max;
for (int i = 0;i < m;i++)
cin >> a[i].spf >> a[i].num;
sort(c, c + n);
sort(a, a + m);
int cnt = 0;
for(int i=0;i<n;i++)
for (int j = 0;j < m;j++)
{//满足条件的最大spf
if (a[j].num == 0) continue;
if (c[i].min<=a[j].spf && c[i].max>=a[j].spf)
{
a[j].num--;
cnt++;
break;
}
}
cout << cnt;
}
max升序排序
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2505;
struct Cow
{
int min;
int max;
bool operator <(const Cow b)const
{
return max < b.max;
}
}c[N];
struct Fang
{
int spf;
int num;
bool operator < (const Fang b)const
{
return spf < b.spf;
}
}a[N];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 0;i < n;i++)
cin >> c[i].min >> c[i].max;
for (int i = 0;i < m;i++)
cin >> a[i].spf >> a[i].num;
sort(c, c + n);
sort(a, a + m);
int cnt = 0;
for(int i=0;i<n;i++)
for (int j = 0;j < m;j++)
{//满足条件的最大spf
if (a[j].num == 0) continue;
if (c[i].min<=a[j].spf && c[i].max>=a[j].spf)
{
a[j].num--;
cnt++;
break;
}
}
cout << cnt;
}