OpenJudge-【3528】:最小新整数

来源:互联网 发布:创作漫画的软件 编辑:程序博客网 时间:2024/05/29 08:20

3528:最小新整数


Description
给定一个十进制正整数n(0 < n < 1000000000),每个数位上数字均不为0。n的位数为m。
现在从m位中删除k位(0 < k < m),求生成的新整数最小为多少?
例如: n = 9128456, k = 2, 则生成的新整数最小为12456

Input
第一行t, 表示有t组数据;
接下来t行,每一行表示一组测试数据,每组测试数据包含两个数字n, k。
Output
t行,每行一个数字,表示从n中删除k位后得到的最小整数。

Sample Input

29128456 21444 3

Sample Output

124561

题目解析
这是一道稍微提高的贪心算法的题目,可以来检验一下学习的结果。
这里的n非常大,一般来说我们用高精度来计算。但是由于这道题并没有诸如加减乘除之类的运算,我们可以在高精度的基础上,不把字符串转换为数字串,而是直接用字符串string(STL的iostream中的字符串类型),这样做还有一个好处,之后再仔细讲解。
输入不多说,我们用for循环来完成多组数据。然后用cin输入string类型的s,注意这里不需要将字符串s反转,也就是说s[0]~s[n]是从高位到低位排列的。我们把输入的删减次数用int类型F储存。用for循环循环F次,每次循环删减一个数。既然是贪心算法,我们就需要得到一个局部最优解——也就是每次循环(删减一个数)所得到的新字符串该次删减中能够得到的字符串中最小的一个。全局最优解与局部最优解的关系比较像递推,删减是依据上一次的删减结果来判断的。
如何得到局部最优解呢?这就需要寻找一些规律:

一个数,若改变它任意一位的数字(最高位不为0),我们很容易发现 —— 改变的位数越高,与原数的差距就越大。

于是,我们可以判断,要得到局部最优解,就要使新数字的越高的位置数越小。这样就可以知道我们应该从高位往低位判断删减,而要让它小,则应该删除较大的数。这里有一个误区——并不是删除原数中较大的数字就是全局最优解,举个例子:

10009 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!


题外话
今天是作者第一天学习贪心,DP暂时搁在一边。如果程序有一些问题,可以在评论中点出,谢谢!


程序样例

/*Lucky_Glass*/#include<cstdio>#include<iostream>using namespace std;int main(){    int H;    scanf("%d",&H);    for(int h=0;h<H;h++)    {        string s;        cin>>s;        int F;        scanf("%d",&F);        for(int f=0;f<F;f++)        {            for(int i=0;i<(int)s.length();i++)                if(s[i]>s[i+1] || i==s.length()-1)                {                    s.erase(i,1);                    break;                }        }        while(s[0]=='0' && s[1])            s.erase(0,1);        cout<<s<<endl;    }    return 0;}

The End

Thanks for reading!


原创粉丝点击