20190511模拟赛
T1:种树
【题目描述】
某条街被划为 n 条路段,这 n 条路段依次编号为 1,2,…,n。每个路段最多可以种
一棵树。现在居民们给出了 h 组建议,每组建议包含三个整数 b,e,t,表示居民希
望在路段 b 到 e 之间至少要种 t 棵树。这些建议所给路段的区间可以交叉。请问:
如果要满足所有居民的建议,至少要种多少棵树。
【输入格式】
第一行为 n,表示路段数。
第二行为 h,表示建议数。
下面 h 行描述一条建议:b,e,t,用一个空格分隔。
【输出格式】
输出只有一个数,为满足所有居民的建议,所需要种树的最少数量。
【样例输入】 tree.in
9
4
1 4 2
4 6 2
8 9 2
3 5 2
【样例输出】 tree.out
5
【说明】
30%的数据满足 0<n<=1000,0<h<=500;
100%的数据满足 0<n<=3104,h<=5000,0<b<=e<=3104,t<=e-b+1
乍一看这道题目,应该就可以确定这是一道贪心了,那么重点是如何找到它的贪心策略呢?我们发现种树的区域是会有重叠的,那么我们就要尽量在重叠的地方种树,这样可以最省。
那么怎么求重叠?明显可以使用排序。我们可以以结束位置为关键字排序,然后从后往前补上该区域内还缺少的树木个数。所以这里就需要一个该区域内树木是否已经足够多的特判。
好了下面上代码:
#include<bits/stdc++.h>
using namespace std;
struct line{
int s,e,v;}a[5005];
int n,m,ans=0;
bool used[30005]={
0};
bool cmp(line a,line b)
{
return a.e<b.e;
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].s,&a[i].e,&a[i].v);
sort(a+1,a+1+m,cmp);
for(int i=1;i<=m;i++)
{
int k=0;
for(int j=a[i].s;j<=a[i].e;j++) if(used[j]) k++;
if(k>=a[i].v) continue;
for(int j=a[i].e;j>=a[i].s;j--)
{
if(!used[j])
{
used[j]=1;
k++;
ans++;
if(k==a[i].v) break;
}
}
}
printf("%d",ans);
return 0;
}
T2:加工生产调度
【题目描述】
某工厂收到了 n 个产品的订单,这 n 个产品分别在 A、B 两个车间加工,并且必
须先在 A 车间加工后才可以到 B 车间加工。
某个产品 i 在 A,B 两车间加工的时间分别为 Ai,Bi。怎样安排这 n 个产品的加
工顺序,才能使总的加工时间最短。
这里所说的加工时间是指:从开始加工第一个产品到最后所有的产品都已在 A,
B 两车间加工完毕的时间。
【输入格式】
第一行仅—个数据 n,表示产品的数量;
接下来 n 个数据是表示这 n 个产品在 A 车间加工各自所要的时间;
最后的 n 个数据是表示这 n 个产品在 B 车间加工各自所要的时间。
【输出格式】
第一行一个数据,表示最少的加工时间;
第二行是一种最小加工时间的加工顺序。
【样例输入】 prod.in
5
3 5 8 7 10
6 2 1 4 9
【样例输出】 prod.out
34
1 5 4 2 3
【数据范围】
对于 100%的数据,0<n<1000,所有数值皆为整数。
本题的 SPJ 对行尾多余空格敏感,各位输出答案时不要留行尾多余空格
(蒟蒻表示在某谷上做到过相(yi)似(yang)的题目……)
看完题目明显发现我们的选择并不会对以后的决定产生影响,即无后效性。所以我们又欢乐的发现,这是一道贪心题……
我们其实只要设计一个排序的方案,然后将其应用到sort函数里去就可以了。那么如何进行寻找呢?
我们可以假设只有两个产品1和2。产品的加工时间分别是 a 1 a_1 a1, a 2 a_2 a2, b 1 b_1 b1, b 2 b_2 b2。那么我们如果先加工产品1,则它的总时间为: a 1 + m a x ( b 1 , a 2 ) + b 2 a_1+max(b_1,a_2)+b_2 a1+max(b1,a2)+b