题目:
键盘输入一个高精度的正整数N(不超过250位) ,去掉其中任意k个数字后剩下的数字按原左右次序将组成一个新的正整数。
编程对给定的N和k,寻找一种方案使得剩下的数字组成的新数最小。
算法思路:
要从正整数中删除k个数字,可以采取一步步来删的策略,每一次删除一个数字,使得当前得到的数字是最小的,执行k步后,即得到最后的结果。
通过子问题的最优解来得到整个问题的最优解,就是贪心的思想。
例如:7122145这个数字,如果k=3,第一次删除的应该是7,得到122145;第二次删除的应该是5,得到12214;第三次删除的应该是4,得到1221.
通过观察,可以发现每次删除的数字有这样的规律:
都是整个数字中递减区间的第一个数字,如果整个数中没有递减区间,就删除最后一个数字,因为要想留下的数字最小,它的高位肯定要尽可能小,
这样删除的方法,在当前次看来都是最优的,我们把降序区间的第一个数删掉,就可以让后面比他小的数前进一个高位,那么数字也就变小了,
如果我们删除了这个最优数字前面的数,那么这个比较大的数字就前进了一个高位,反而让数字变大了,
同样的,如果我们删除这个数后面的也很大的数字,虽然能让小的数也前进一个高位,但是它本身处的位置也很低,显然没有让利益最大化。
上代码:
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 int main() { 5 string n; 6 int k; 7 cin >> n; 8 cin >> k; 9 while (k != 0) { 10 int flag = 0; 11 for (int i = 0; i < n.length()-1; i++) { 12 if (n[i] > n[i + 1]) { 13 n.erase(i, 1); 14 flag = 1; 15 break; 16 } 17 } 18 //如果数字都是单调递增的,就删除最后一个 19 if(!flag) n.erase(n.length() - 1, 1); 20 k--; 21 } 22 int i = 0; 23 if (n == "0") { 24 cout << n; 25 return 0; 26 } 27 //将首位的0去掉 28 while (n[i] == '0') { 29 i++; 30 } 31 for (int j = i; j < n.length(); j++) { 32 cout << n[j]; 33 } 34 35 return 0; 36 }
其中,string中的erase()函数的用法在我的另一篇博客中有总结。