本次训练内容为贪心,也是普及组初赛非常喜欢考察的内容,大家务必要搞懂这个算法。
贪心就是不考虑整体情况,只取到达下一阶段哪个最优,即取局部最优解。和动态规划全局最优解不同
贪心的证明非常复杂(一般用数学归纳法、反证法等证明)。
1.6965 最优服务次序问题
我们用T(i)表示第i个顾客的等待时间,t(i)表示第i个顾客的服务时间
第一个顾客要等T(1)时间,为0
第二个同学要等T(2)时间,为t(1)
第三个同学要等T(3)时间,为t(1)+t(2)
...
第三个同学要等T(n)时间,为t(1)+t(2)+...+t(n-1)
等待总时间为 T=(n-1)*t(1)+(n-2)*t2+...+1*t(n-1)
要想让T最小,系数已经确定,那么我们只需要让t(1)、t(2)依次变大即T最小
#include<bits/stdc++.h>
using namespace std;
int a[100005];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
double sum=0;
for(int i=0;i<n;i++)
{
sum+=a[i]*1LL*(n-i-1);
}
printf("%.2f
",sum/n);
return 0;
}
2.6923 tencent's 商店
对应为1004 渊子赛马,我们需要让其正好能够买到,注意不要下标越界
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N], b[N];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++)
cin >> a[i];
for (int i = 0; i < m; i++)
cin >> b[i];
sort(a, a + n);
sort(b, b + m);
int i = n-1, j = m-1, ans = 0;
while (i>=0 && j>=0)
{
if (a[i] >= b[j])
{
ans++;
i--;
}
j--;
}
cout << ans << "
";
}
3.5594 区间问题
按照右端点排序,能先做完的先做,记录一下结束时间,判断下次是否可以做
#include<bits/stdc++.h>
using namespace std;
struct T{int l,r;}a[100005];
bool cmp(T a,T b){return a.r<b.r;}
int main()
{
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)cin>>a[i].l;
for(int i=0;i<n;i++)cin>>a[i].r;
sort(a,a+n,cmp);
int num=0,R=-1;
for(int i=0;i<n;i++)
{
//可以做,就选择
if(R<a[i].l)num++,R=a[i].r;
}
cout<<num<<"
";
}
return 0;
}
4.2668 Lecture Halls (会议安排)
与上一题不同,不是不能做了就开间会议室,你新开的会议室接下来还可能要使用
可以把左右端点分别排序去考虑
5.5625 Kannyi爱种树
为区间覆盖问题,需要考虑分离、相交和包含,属于1532 校门外的树加强版
6.4879 积木大赛
如果当前的比现在的高,那么说明当前需要多盖两个的差;比现在的矮,说明选择的区间要截断,而且之前已经把当前的盖过了。所以只和前一个有关。