算法第四章上机实践报告
一、 实践题目
4-1 程序存储问题 (90 分)
设有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
二、 问题描述
先输入程序个数和磁带长度,下一行依次输入每个程序的长度,从而选择一种储存方式使得储存的程序个数最多(选择的程序总长不能超过磁带长度)。
要尽可能多的储存程序,那么只需要每次都挑最短的加入进磁带即可,用到贪心算法的思维,可描述为:
式中,变量xi=0表示第i个程序不装入磁带,xi=1表示第i个程序装入磁带,L是磁带总长,li是第i个程序的长度。
三、 算法描述
1、贪心算法
sort(a,a+n); int p = 0, count = 0; for(int i = 0; i < n; i++) { count += a[i]; if(count <= m) { p++; } }
策略:每次都选择长度最小的加入(用sort直接按从小到大排好序)
证明:
设程序长度按从小到大排序,(x1,x2,…,xn)是一个最优解,设k = min { i | xi = 1 }(1≤i≤n),如果该问题有解,则1≤k≤n。
① 当k=1时,(x1,x2,…,xn)是一个满足贪心选择性质的最优解。
② 当k>1时,取y1=1,yk=0,yi=xi,1<i≤n,i≠k,则
因此,(y1,y2,…,yn)是所给问题的可行解。
另一方面,由知,(y1,y2,…,yn)是满足贪心选择性质的最优解。
最优子结构:
设(x1,x2,…,xn)是该问题的满足贪心选择性质的最优解,则x1=1,(x2,x3,…,xn)是磁带可用长度为L-l1、待选择程序为{2,3,…,n}时相应最优装载问题的最优解。也就是说,该问题具有最优子结构性质。
2、判断是否超过总长度
将从小到大的排好序的程序依次加入磁带,如果超出总长度就停止。用一个变量count来记录已用长度,用p来记录加入的程序数。
3、完整代码
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 int main(){ 5 int n,m; 6 cin>>n>>m; 7 int a[n]; 8 for(int i = 0; i < n; i++) { 9 cin>>a[i]; 10 } 11 sort(a,a+n); 12 int p = 0, count = 0; 13 for(int i = 0; i < n; i++) { 14 count += a[i]; 15 if(count <= m) { 16 p++; 17 } 18 } 19 cout<<p<<endl; 20 return 0; 21 }
完整代码
算法时间及空间复杂度分析
sort排序+循环遍历所有程序,不断加入磁带直到达到最大长度限制,所以时间复杂度为O(n),这里贪心算法只是一个sort排序,贪心算法的时间复杂度为O(nlogn)。
解这道题中,只用到了存储数据的本来的数组a[n],将本来的数组进行排序,没有用到辅助空间。
四、 心得体会
贪心问题,做起来我自己感觉,比起前面的动态规划,分治问题都要简单许多。就是在寻找一个贪心策略,举出反例的话就换一个,最后得到最好的,一般都是“最什么什么的”策略,很好想,也较好打出代码。
原文地址:https://www.cnblogs.com/990924991101ywg/p/11876844.html