贪心算法常见题型
(1)小数背包问题
题目描述
有一个背包,背包容量是M(0<M≤500),有N(1<N≤1000)个物品,物品可以分割成任意大小。
要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。
输入
第1行有两个数,M和N;
第2行到N+I行:第i行为第i-1个物品的价值和质量(均为小于100的正整数),中间用空格隔开。
输出
只有一个数为最大总价值(保留一位小数)。
样例输入
150 7
10 35
40 30
30 60
50 50
35 40
40 10
30 25
样例输出
190.6
这种问题由于物品可拆分成任意大小,所以我们只需要根据单位价值来进行选择即可得到最优解。
#include <bits/stdc++.h>
using namespace std;
typedef struct
{
int zl,jz;
double dw;
}bb;
double cmp(bb x,bb y)
{
return x.dw>y.dw;
}
int main(){
int m,n;
cin>>m>>n;
bb a[n];
double s=0,t=0;
for(int i=0;i<n;i++)
{
cin>>a[i].jz>>a[i].zl;
a[i].dw=1.0*a[i].jz/a[i].zl;
}
sort(a,a+n,cmp);
for(int i=0;i<n;i++)
{
if(t+a[i].zl<=m)
{
s+=a[i].jz;
t+=a[i].zl;
}
else
{
s+=(m-t)*a[i].dw*1.0;
break;
}
}
cout<<fixed<<setprecision(1)<<s<<endl;
return 0;
}
(2)分组问题
题目描述
元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。
输入
输入包含n+2行:
第1行包括一个整数w,为每组纪念品价格之和的上限; 第2行为一个整数n,表示购来的纪念品的总件数G
第3-n+2行每行包含一个正整数Pi (5 <= Pi <= w)w表示所对应纪念品的价格。
100%的数据满足: 1 <= n <= 30000, 80 <= w <= 200
输出
仅1行,包含一个整数, 即最少的分组数目
样例输入
100
9
90
20
20
30
50
60
70
80
90
样例输出
6
两端同时取
#include <bits/stdc++.h>
using namespace std;
int main()
{
int m,n;
cin>>m>>n;
int a[n];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
int x=0,y=n-1,cnt=0;
while(x<=y)
{
if(a[x]+a[y]<=m)
{
cnt++;
x++;
y--;
}
else
{
cnt++;
y--;//放不下就只放a[y]一个
}
}
cout<<cnt<<endl;
return 0;
}
(3)节目安排问题
题目描述
李旭琳发现小墨老师在班上是最顽劣的学生(没有之一),但他也有安静的时候,例如在看电视的时候。像什么“谍战剧”啊,“翻拍剧”啊,“婆媳戏”啊,“后宫剧”啊都是他的最爱。他甚至会事先查询所有喜欢看的电视节目的转播时间表并煞有介事的用红蓝铅笔列出计划,然后合理安排,以看到尽量多的完整节目。
输入
第一行只有一个整数n(n≤100),表示喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1≤i≤n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。
输出
输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
样例输入
12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
样例输出
5
对于这种问题,我们往往采用右端点排序法(为什么不用左端点,你可以试一试)
#include <bits/stdc++.h>
using namespace std;
typedef struct
{
int ks,js;
} qj;
int cmp(qj x,qj y)
{
return x.js<y.js;
}
void fun(int n,qj a[],int cnt)
{
int j=0;
cnt=1;//第一个肯定在
for(int i=1; i<n; i++)
{
if(a[i].ks>=a[j].js)//根据具体情况分析是否可以等于
{
j=i;
cnt++;
}
}
cout<<cnt<<endl;
}
int main()
{
int n;
cin>>n;
qj a[n];
int x,y,cnt;
for(int i=0; i<n; i++)
{
cin>>a[i].ks>>a[i].js;
}
sort(a,a+n,cmp);//右端点排序
fun(n,a,cnt);
return 0;
}
练习题
(1)闭区间问题
题目描述
通过魔法钟回来的张琪曼和魔法学院的其他学员一起研究营救李旭琳脱离“时空陷”的方法。他们建立了n个对历史时间线的监控点,每个监控点可监控历史上的一个时间段,我们可以简单地看做是 x 轴上 n 个闭区间。但有些监控点监控的时间段是重叠的,这会干扰监控的准确性。请尝试去掉尽可能少的闭区间,使剩下的闭区间都不相交。
输入
第一行为闭区间的个数n(1≤n≤40000),随后n行为闭区间的2个端点。
输出
输出去掉尽可能少的闭区间的个数。
样例输入
3
10 20
15 10
20 15
样例输出
2
(2)监测点
题目描述
“多么希望有一天突然惊醒,发现自己是在小学的一节课上睡着了,现在经历的一切都是一场梦,桌上满是你的口水。你告诉同桌,说做了一个好长好长的梦。同桌骂你白痴,叫你好好听课。你看着窗外的球场,一切都那么熟悉,一切还充满希望……”张琪曼通过时空监测点听到40年前的小墨老师对李旭琳这样说。话说张琪曼等人将历史时间线划分了n个区域,我们可以将之看成是数轴上的n个闭区间[ai,bi]。现要设置尽量少的监测点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个),请问需要多少个监测点?
输入
第一行为一个整数X,表示有X组数据,每组数据第一行为一个整数n(N≤100),表示有n个闭区间,随后n行每行为两个整数,表示区间左端a和右端b(0≤a≤b≤100)。
输出
一个整数,即监测点个数。
样例输入
1
3
1 5
2 8
6 9
样例输出
2
今天的分享就到这里(本人刚接触计算机,轻点喷)