算法第四章上机实验报告
算法第四章上机实验报告
一、实验题目
4-2 删数问题 (30 分)
给定n位正整数a,去掉其中任意k≤n 个数字后,剩下的数字按原次序排列组成一个新的正整数。对于给定的n位正整数a和正整数 k,设计一个算法找出剩下数字组成的新数最小的删数方案。如果数字最前面有0不输出。
输入格式:
第 1 行是1 个正整数 a。第 2 行是正整数k。
输出格式:
输出最小数。
输入样例:
在这里给出一组输入。例如:
178543
4
结尾无空行
5001
1
结尾无空行
123456
2
结尾无空行
109
1
结尾无空行
输出样例:
在这里给出相应的输出。例如:
13
结尾无空行
1
结尾无空行
1234
结尾无空行
9
结尾无空行
二、贪心算法选择
依次删除第一段递增子序列的最后一个值
贪心策略分析:
按题目所给的第一个例子来看,删除178543中的四个数字,得到最小的两位数。按照常规思维我们会选择其中四个较大的数字进行删除,在这个例子中也可以得到正确答案。但是如果所给的数是305462,删除一个数字,选择最大的数6,所得的数为30542,而如果删除5,所得的数为30462,很明显,此时30542>30462,因此证明选择较大数字进行删除的贪心策略是行不通的。原因在于题目所给的条件:剩下的数字按原次序排列组成一个新的正整数。所以在305462这个数中,即使6是这个数最大的那个数字,但是因为不能打乱顺序,5所在的位次比6高,删除5后的数字会比删除6后的数字小。而5正好是这个数中递增序列的最后一个数字。所以此题的贪心策略是依次删除第一段递增子序列的最后一个值。经检验,此方法可行。
三、题目代码
#include <iostream> #include <cstring> using namespace std; /* run this program using the console pauser or add your own getch, system("pause") or input loop */ int main(int argc, char** argv) { char a[1000]; int k; int len; cin >> a >> k; len = strlen(a); for(int i = 0; i < k; i++) { for(int j = 0; j < len; j++) { if(a[j + 1] > a[j]) continue; else { for(int i = j; i < len; i++) { a[i] = a[i + 1]; } len--; break; } } } bool flag = false; for(int i = 0; i < len; i++) { if(a[i] != '0') flag = true; if(flag) cout << a[i]; } return 0; }
四、算法时间复杂度
O(n)= n^2
五、对贪心算法的理解
贪心算法需要找到最优解,而往往有时候我们习以为常的最优解决方案并不是题目的最优解,因此需要进行多次举例尝试,避免出现找错贪心算法策略的问题。找出贪心算法策略后,也要反复进行验证。