算法第四章《贪心策略》上机实践报告
一.实践题目名称
删数问题
二.问题描述
给定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
三.算法描述(使用什么贪心策略)
因为新数是按照剩余数字的原序组合而成的,所以采用的贪心策略是尽量让高位数字最小使剩余数字组成的新数最小。那么应该从左到右依次遍历每一位数,删除递减序列的第一位数字,如果找不到(即该串数字是递增序列),就删除最后一位数字。
该过程循环执行k次,若有前导0舍去再输出。
#include<iostream> #include<cstring> using namespace std; int main() { char a[100]; cin >> a; int k; cin >> k; int len = strlen(a); //a的位数 for (int i = 0; i < k; i++) { for (int j = 0; j < len - 1; j++) { if (a[j] > a[j + 1]) { for (int m = j; m < len; m++) //删除第j位,将后面的数字往前移一位 a[m] = a[m + 1]; break; } } len--; } int i = 0; while (a[i] == '0' && i < len) i++; if (i == len) cout << 0; else for (; i < len; i++) cout << a[i]; return 0; }
四.算法时间及空间复杂度分析
时间复杂度:若找到递减序列第一位则将后面的数往前移一位,否则删除最后一位数,故每需要删除一位数就要进行一次数组的遍历,时间复杂度为O(n*k)。
空间复杂度:算法只使用了普通变量,空间复杂度为O(1)。
五.心得体会(对本次实践收获及疑惑进行总结)
1.在实验课上,我读完题目以后便先入为主地认为如果要使新数最小,应该每次都删去序列中最大的数字。尽管老师提供的三个测试点都通过了,但是我把代码提交到pta上却发现部分错误。同学提示我假如测试点是1005,按照这种方法来看新数为100,但正确答案应该为5。这说明这种策略是不可行的,应该转换思路为尽量让高位数字最小使剩余数字组成的新数最小。
2.贪心算法的使用关键在于贪心策略的选择,要找到合适的策略,需要认真分析题目,大胆尝试,失败后要勇于推翻之前的策略,重新思考找到方向。
六.对贪心算法的理解和体会
贪心算法的着眼点是当前情况的最优解,算法实现直接快捷,如果能正确找到合适的贪心策略固然优先使用。但局部最优解不一定得到整体最优解,如果在一些情况下使用贪心算法不能得到最优解,应改为使用动态规划法。