删数问题

//洛谷 P1106 删数问题 
//此题与 1231 最小新整数 基本雷同
//1231 最小新整数
//感觉题目比较简单,将最大的数由大到小删除
//样例通过,但提交,未通过
//总觉得算法不对,因为删的是最大的数,但又举不出反例
//http://blog.csdn.net/c20190102/article/details/52350828此文介绍得真不赖,摘抄如下:
//此题先看看思路:
//如果是直接删掉最大的数字,很容易便可举出反例:
//1529 1
//如果直接删最大的9,结果为152,如果删掉5,结果为129,显然删掉5才是最佳答案。
//再看一组数据:
//141519 2
//如果删最大的9,5,结果为1411,如果删掉4,5,结果为1119,显然删掉4,5才是最佳答案。
//发现什么了吗?
//先看第一组:
//1  5  1  9
//小大 小 大
//留删 留 留
//第二组:
//1   4  1  5  1   9
//小 大 小 大 小 大
//留 删 留删 留 留
//删掉的是“山峰”,也就是比后一个数大的数,且越靠前“山
//峰”越早删。
//大体思路也就一句话:删除靠前的“山峰”。
//另外,有几个坑不得不提:
//1.注意删除前导0(虽然它说每个数位都不为0,但是测试数据里面好像有这样的数据)。
//2.删过一个数记得长度len--。
//3.有多组数据(其实数组可以不清零,因为有len控制查找范围)。
//4.当把数删为0(见数据4)时,要输出0。
//另外送大家几组数据(我就在此栽过跟头):
//   输入                       输出
//133420 2                   120
//1444 3                        1
//20018 2                      1
//10000 1                      0
//http://blog.csdn.net/qq_25734657/article/details/52329863代码简练,此文也写得不错,摘抄如下:
//1243865 1怎么删呢?如果你认为是删8,那就错了。如果删8,得124365,但如果删4,得123865,哪个更小呢?毫无疑问是后者吧。那如果是1244444 5呢?最后删到124就删不掉了,所以还有一个条件,如果删了一遍,删不掉,就删去最后一个。大概意思就是这样,由于这道题没有出现有0的情况,所以我在这里暂时不讨论,可以自己想想。
//代码彻底推翻重来,样例通过,提交,未通过,
//少了break,修改,提交AC 2017-11-2 22:26 
//提交,测试点2,6答案错误 
//提供两组测试数据
//输入:
//20018 2
//输出:
//1
//输入:
//10000 1
//输出:
//0 
//针对上述两组输入输出数据进行修改,提交AC 2017-11-26 17:13 
#include <stdio.h>
#include <string.h>
char c[260];
int main(){
    int len,i,j,s;
    scanf("%s%d",c,&s);
    len=strlen(c);
    while(s--){
        for(i=0;i<=len-2;i++)
            if(c[i]>c[i+1]){
                for(j=i;j<=len-2;j++)
                    c[j]=c[j+1];
                break;
            }
        len--;//此处位置写错,之前写在if内部
    }
    i=0;
    while(i<=len-1&&c[i]=='0')i++;//处理前导0 
    if(i==len)printf("0");
    else
        for(j=i;j<=len-1;j++)
            printf("%c",c[j]); 
    return 0;
} 






我的思路与下面的各位大佬有点不一样。因为题目最终求的是删数后最小的一个数,其实我们可以将问题直接转换为保留几位数字,使最后的数最小。于是,就有贪心的算法了:

首先,考虑第一位。将第一位所有可能的位置枚举一下,取最小且最前的一个。因为同样长度的数字比较看开头,于是这样便保证了第一位的最优性。要注意,要取最前的一个,尽量保留更多的可选数。而第二位就在第一个数之后的所有允许范围内枚举,方法同第一位。这样,取完了所有要取的数,然后输出就可以了。

这里注意一下,题目并没有很明确的说要去掉前导零,但是事实上数据是要去的。

代码如下:

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
int main()
{
    char num[500];
    int gs,bl;
    scanf("%s%d",num,&gs);//读入
    int len=strlen(num);//取总长
    bl=len-gs;//得到需要保留的数的个数
    int shu[500];
    for(int i=0;i<len;i++)shu[i]=num[i]-'0';//转化为整数类型,并存储
    int bln[500],js=0,sgw=-1;//注意初始化,上一个开头要取-1,因为第一位有可能取第0个
    int lim,minn;
    while(bl-js)//即枚举bl次
    {
        minn=2e9;//初始化,minn=inf
        for(int i=sgw+1;i<=len-bl+js;i++)if(shu[i]<minn)minn=shu[sgw=i];//取最小且最前的数
        bln[js++]=shu[sgw];//加入到数中
    }
    int start=0;
    while(bln[start]==0&&bl-start-1)start++;//去前导零
    for(int i=start;i<bl;i++)printf("%d",bln[i]);//输出
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值