目录
一、概述
二、活动安排问题
三、背包问题
四、最优装载问题(件数最多)
五、删数问题
六、汽车加油问题
七、果子合并(openjudge题目)
4.贪心算法和动态规划算法比较
共同点:
都是求最优解的选择性算法
所解决的问题都具有最优子结构性质,即全优一定包含局优
不同点:
5.利用贪心策略解题,需要解决以下两个问题:
(1)该题是否适合于用贪心策略求解(贪心选择性质+最优子结构性质)
(2)如何选择贪心标准,以得到问题的最优/较优解
描述
学校的小礼堂每天都会有许多活动,有时间这些活动的计划时间会发生冲突,需要选择出一些活动进行举办。小刘的工作就是安排学校小礼堂的活动,每个时间最多安排一个活动。现在小刘有一些活动计划的时间表,他想尽可能的安排更多的活动,请问他该如何安排。
输入
每组测试数据的第一行是一个整数n(1 随后的n行,每行有两个正整数Bi,Ei(0<=Bi,Ei<10000),分别表示第i个活动的起始与结束时间(Bi<=Ei)
输出
对于每一组输入,输出最多能够安排的活动数量。
每组的输出占一行
分析:
代码:
#include
#include
#include
using namespace std;
struct action
{
int s;//活动起始时间
int f;//活动结束时间
int index;//活动编号
}a[101];
bool cmp(const action&a,const action &b)
{
if(a.f<=b.f)
return true;
else
return false;
}
int main()
{
int n,b[101];
cin>>n;
for(int i=0;i>a[i].s>>a[i].f;
a[i].index=i+1;
}
sort(a,a+1+n,cmp);
int sum=0;
for(int i=2;i<=n;i++)
{
if(a[i].s>=a[i-1].f)
{
sum++;
cout<
给定一个载重量为M的背包,考虑n个物品,其中第 i 个物品的重量 wi ,价值vi (1≤i≤n),要求把物品装入背包,且使背包内的物品价值最大。物品可分割
单位重量价值:vi/wi,把单位重量价值加性价比,即按性价比从高到低的顺序选取物品
#include
#include
#include
using namespace std;
struct bag
{
int w;//物品的重量
int v;//物品的价值
double c;//单位重量的价值,v/w
}a[101];
bool cmp(bag a,bag b)
{
if(a.c>=b.c)
return true;
else
return false;
}
int main()
{
int n;//物品数量
int c;//背包容量
cin>>n>>c;
double b=0;//装入背包的价值
int cleft=c;//背包剩余容量
for(int i=0;i>a[i].w>>a[i].v;
a[i].c=a[i].v/a[i].w;
}
sort(a,a+n,cmp);
for(int i=0;i
如果要同时得到解向量,即每件物品装了多少到背包,结构体加
double x; //装入背包的量,0≤x≤1,初值都为0
int index; //物品编号
- 如果第i件物品全部装入:a[a[i].index].x = 1.0;
- 如果第i件物品部分装入:
a[a[i].index].x = cleft/a[i].w;
b += a[a[i].index].x*a[i].v;
有一批集装箱要装上一艘载重量为 c 的轮船,其中集装箱 i 的重量为 wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船(件数最多)
输入:
重量c,集装箱个数n;
接下来分别输入n个集装箱重量a[i]
输出:
第一行:能装的最多件数
第二行:装入的集装箱编号
分析:
既然要求件数最多,即采用重量最轻者先装的贪心选择策略
代码:
#include
#include
#include
using namespace std;
struct load
{
int index;//编号
int w;//重量
}a[101];
bool cmp(load a,load b)
{
if(a.w>c>>n;
memset(a,0,sizeof(a));
memset(x,0,sizeof(x));//初值都是0
for(int i=1;i<=n;i++)
{
cin>>a[i].w;
a[i].index=i;
}
sort(a,a+n+1,cmp);
if(a[1].w>c)//一个都装不进去
{
cout<<"No answer!"<
给定n位正整数a,去掉其中任意k≤n个数字后,剩下的数字按原次序排列组成一个新的正整数。对于给定的n位正整数a和正整数k,设计一个算法找出剩下数字组成的新数最小的删数方案(顺序不改变)
输入:
第1行是1个正整数a,第2行是正整数k。//k是删除数字的个数
例如:178543 4
输出: 13
对于给定的正整数a,编程计算删去k个数字后得到的最小数。
分析:
删数问题找第一个不下降的数,删掉 即寻找最近下降点
输入:字符串格式
存储:数组,整数数组或者字符数组
代码:
#include
#include
#include
using namespace std;
struct load
{
int index;//编号
int w;//重量
}a[101];
bool cmp(load a,load b)
{
if(a.w>a>>k;
if(k>=a.size())
a.erase();//如果k≥n,所有数字均被删除
else
{
while(k>0)
{
int i;
for(i=0;(i1&&a[0]=='0')//删除前导数字0
a.erase(0,1);
cout<
一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。对于给定的n(n <= 5000)和k(k <= 1000)个加油站位置,编程计算最少加油次数。
输入:
第一行有2个正整数n和k,表示汽车加满油后可行驶n公里,且旅途中有k个加油站
接下来的1行中,有k+1个整数,表示第k个加油站与第k-1个加油站之间的距离。第0个加油站表示出发地,汽车已加满油。第k+1个加油站表示目的地。
输出:
最少加油次数。如果无法到达目的地,则输出”No Solution”。
分析:
1、到达加油站之后,看看剩余的油能否跑到下一个加油站;
能,则不用加油 否则,加油
2、一个变量表示到达该站前需要行驶距离 s1
3、一个变量表示到达下一个还需要行驶距离s2即station[i]
如果n-s1
代码中:如果s1>n,加油,s1=station[i]
#include
#include
#include
using namespace std;
int main()
{
int n,k;// 加满油可行驶距离、k个加油站
cin>>n>>k;
int station[k+1];//加油站之间的距离,有k+1个
for(int i=0;i<=k;i++)
cin>>station[i];
int s1=0,number=0;//s1到达该站前需要行驶距离,number记录加油的次数
s1=station[0];//到达第一个加油站需要走s1
for(int i=1;i<=k;i++)
{
if(s1>n)//走不过去
{
cout<<"No solution!";
break;
}
else
{
s1=s1+station[i];
if(s1>n)
{
number++;//加油
s1=station[i];//加满油之后s1重新赋值,表示到下一站要行驶的距离
cout<<"在第"<
描述:
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n-1n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 11 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有 33 种果子,数目依次为 11 , 22 , 99 。可以先将 11 、 22 堆合并,新堆数目为 33 ,耗费体力为 33 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 1212 ,耗费体力为 1212 。所以多多总共耗费体力 =3+12=15=3+12=15 。可以证明 1515 为最小的体力耗费值。
输入:共两行。
第一行是一个整数 n(1≤n≤10000) ,表示果子的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 a_i(1≤ai≤20000) 是第 i 种果子的数目。
输出:
一个整数,也就是最小的体力耗费值。
代码:
#include
#include
#include
using namespace std;
int main()
{
int n,a[101],sum=0;//几堆果子,每堆果子数目
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+n+1);//从小到大排序
for(int i=2;i<=n;i++)
{
sort(a+i-1,a+n+1);//每操作完一次 就排一次序
a[i]+=a[i-1];//将第a[i]变为两堆消耗体力值的和
sum+=a[i];
}
cout<