#3946. 最小新整数
最小新整数
最小新整数 Description 给定一个十进制正整数n(0 < n < 1000000000),每个数位上数字均不为0。n的位数为m。 现在从m位中删除k位(0 < k < m),求生成的新整数最小为多少? 例如: n = 9128456, k = 2, 则生成的新整数最小为12456
输入
第一行t, 表示有t组数据; 接下来t行,每一行表示一组测试数据,每组测试数据包含两个数字n, k。
输出
t行,每行一个数字,表示从n中删除k位后得到的最小整数。
输入样例
2 9128456 2 1444 3
输出样例
12456 1
题目解析
这是一道稍微提高的贪心算法的题目,可以来检验一下学习的结果。 这里的n非常大,一般来说我们用高精度来计算。但是由于这道题并没有诸如加减乘除之类的运算,我们可以在高精度的基础上,不把字符串转换为数字串,而是直接用字符串string(STL的iostream中的字符串类型),这样做还有一个好处,之后再仔细讲解。 输入不多说,我们用for循环来完成多组数据。然后用cin输入string类型的s,注意这里不需要将字符串s反转,也就是说s[0]~s[n]是从高位到低位排列的。我们把输入的删减次数用int类型F储存。用for循环循环F次,每次循环删减一个数。既然是贪心算法,我们就需要得到一个局部最优解——也就是每次循环(删减一个数)所得到的新字符串该次删减中能够得到的字符串中最小的一个。全局最优解与局部最优解的关系比较像递推,删减是依据上一次的删减结果来判断的。 如何得到局部最优解呢?这就需要寻找一些规律:
一个数,若改变它任意一位的数字(最高位不为0),我们很容易发现 —— 改变的位数越高,与原数的差距就越大。
于是,我们可以判断,要得到局部最优解,就要使新数字的越高的位置数越小。这样就可以知道我们应该从高位往低位判断删减,而要让它小,则应该删除较大的数。这里有一个误区——并不是删除原数中较大的数字就是全局最优解,举个例子:
10009 1 1 若删除较大的数字则应该删除9,得到1000,但是正确的答案是9——删除1。这个答案的解法有2种,这两种解法描述不同,但是都是指一个东西:
1.若整个字符串为完全非下降序列(前一个数字比后一个数字小或相等,例如123345),则删除字符串的最后一个数字。否则删除第一个下降串的第一个数字(如123421,第一个下降串是421,则删除4)。 2.每次删减掉第一个不下降串的最后一个数字。
仔细理解能够发现他们是指的一个数字。比如1452325,解法1的是第一个下降串“52”,则删除的是原串的第3个数字“5”;解法2的是第一个非下降串“145”中的“5”,同样是第3个数字! 接下来就是实现代码(这里作者选用解法2)。用for循环遍历当前字符串,当s[i]>s[i+1](第一个非下降结束)或者i==s.length()-1(字符串的末尾)时,删除第i个元素。这里有一个作者用string的原因——string的函数特别多,这里就有一个函数专门删减原串中的一段元素的函数“erase”,s.erase(x,len)表示删除字符串s中从x开始的len个元素,这里用s.erase(i,1),也就是删除i元素本身。由于每次只删除一个数,删除过后就用break跳出循环。 最后输出,注意删除前导0!
Limitation
1s, 1024KiB for each test case.