目录
一、程序存储问题
问题描述:
设有n 个程序{1,2,…, n }要存放在长度为L的磁带上。程序i存放在磁带上的长度是 li,1≤i≤n。 程序存储问题要求确定这n 个程序在磁带上的一个存储方案, 使得能够在磁带上存储尽可能多的程序。 对于给定的n个程序存放在磁带上的长度,计算磁带上最多可以存储的程序数。
输入格式:
第一行是2 个正整数,分别表示文件个数n和磁带的长度L。接下来的1行中,有n个正整数,表示程序存放在磁带上的长度。
输出格式:
输出最多可以存储的程序数。
输入样例:
6 50
2 3 13 8 80 20
输出样例:
5
1. 说明”程序存储问题“的贪心策略
显然,为了使磁带上存储的程序数尽可能多,我们需要在还未放置在磁带上的程序中选择长度最短的程序放入磁带,从而达到最后我们能放入的磁带数尽可能多的目的。
所以先排序,用内置函数sort()实现,使得数组变为一个非递减序列,从左向右依次选取元素直至磁带已经无法再放下任何一个程序。
2. 代码实现
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(int a, int b) {
return a < b;
}
int main() {
int n, L;
cin >> n >> L;
int l[n];
for (int i = 0; i < n; i++)
cin >> l[i];
sort(l, l+n, cmp);
int count = 0;
for(int i = 0; i < n; i++) {
L -= l[i];
if(L>=0)
count++;
}
cout << count;
return 0;
}
3. 并用反证法证明满足贪心选择性质
贪心选择的性质是指,所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。
猜想:
对数组进行排序,实现从左到右为非递减序列,从最左边开始,依次选取程序存放到固定长度的磁带中,这样能存放的程序数是最多的。
假设磁带长为L,排好序的程序编号依次为l1,l2,l3 …… ln
最优解为:l1,l2,l3
反证法证明:
假如我们这样选择最终能存放的程序段不是最多。
假设我们先选取l1,之后我们不选取剩余程序段中最小的,我们选择l3放入磁带中,之后我们接着不选l2,计划于l4,l5……ln(假设没有和l2一样长的了)中选择下一个放入的程序段,但由于这是个非递减序列,我们不可能再找到除l2外可以放入磁带的程序段,但我们不选取最小的,故最终解为:l1,l3
显然原答案所得到的程序数量是3,大于我们这样选取得到的数量2,因此不可能在有别于我们猜想的方法中得到更优解,假想得证。
4. 给出时间复杂度分析
在该题中,时间花费最大的是排序,系统内置sort()用的是快排,快排算法平均情况下的时间复杂度是O(nlog2),故 T(n) = O(nlog2)。
二、 我对贪心算法的理解
贪心算法就是不断地做贪心选择,整体的最优解可以通过局部最优解来达到,每一次贪心选择都于最优解中,与动态规划的区别在于,动态规划每一次选择不一定与所求的最优解中,但常常能帮助得到最优解,最优解是需要借助子问题解决时所填的表来实现的。