贪心算法——删数问题

已经很久没有和大家见面了!今天给大家带来的是贪心算法中的一类问题——删数问题。
那么首先我们要了解:贪心算法是什么???
所谓贪心算法,当然是很贪心的算法。就是鼠目寸光地从局部看全局,首先得到局部的最优解,从而推导出全局的最优解。但是这种算法有时候并不适用,乱用会导致进入误区。
例如这一道题:
在一个长n宽m的矩形中,有n*m数,若要从左下角走到右上角,且只能向右或向上走,问经过的数字之和最大是多少。
利用贪心的思想:从1开始,有两条路——2或3,因为2<3,所以选3,然后4、6。总和为14,最大。

36
24
13

但有这样一个例子:可见贪心算法为了3-2得到的1舍去了去10的道路,14<1+2+10+6,真不愧是“贪心”算法啊!

106
24
13

好了,介绍的都介绍完了。接下来我们进入正题——删数问题!
有一个长度为n(n <= 240)的正整数,从中取出s(s < n)个数,使剩余的数保持原来的次序不变,求这个正整数经过删数之后最小是多少。

输入:178543 4
样例输出:13

那么刚拿到这道题如何去思考呢?我们可以先试着找规律。
如果要从178543中取出1个数,使这个数最小,应该取……
8
如果要从17543中取出1个数,使这个数最小,应该取……
7
如果要从1543中取出1个数,使这个数最小,应该取……
5
……
可以发现:1,7,8是一个不降序数列(有相等的升序),也就是逐渐变多,而8,5,4,3是一个不升序数列(有相等的降序),逐渐减少。
8正好是升序数列的最后一个,也是降序数列的第一个。
其他几组也是同样的道理。

那么这样就好办了!我们只需要找到第一个升序数列的末尾并取出它就可以算成功完成了“局部的最优解”,再通过这个继续取出更多的数,直到取出s个数来,从局部的最优解进阶到全局的最优解,这一道题就完成了!

以下为参考程序:

#include<cstdio>
#include<cstring> //格式化输入输出头文件和字符串头文件
char n[250];        //利用字符数组来储存高精度数
int s,i,len,flag=1;
int main()
{
    scanf("%s %d",n,&s);
    len=strlen(n);             //这里是长度函数,取n的长度并赋值给len
    while(s!=0)              //只要s不是0,取数的工作就没有做完!
    {
        i=0;
        while(n[i]<=n[i+1]) //括号内的条件保证了不降序的条件,当它退出时,就是升序数列的末尾了
            i++;
        while(i<len-1)         //这时已经找到了要取出的数——n[i],这是取出的过程
        {n[i]=n[i+1];i++;}         //其实这个循环可以用erase(i,1);代替
        len--;                //取出后数字长度减1
        s--;                   //消耗掉一次取出次数
    }
    for(int i=0;i<len;i++)         //输出时要小心最高位是0的问题!处理输出……
    {
        if(n[i]=='0'&&i<len-1&&flag==1)  //如果即将输出的这一位是0且是最高位而且不是最后一个
            continue;           //跳过
        else
        {printf("%c",n[i]);flag=0;}//输出并且明确n[i]不再是最高位
    }
    return 0;
}

当然,我的做法仅供参考。希望大家多多改进!

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/qq_37630072/article/details/77369083
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞