洛谷P1106 删数问题——按步骤的贪心法

贪心法可以解决的问题,就是两大类,一种是对元素的贪心,另外一种就是我们这里要讨论的步骤贪心。

洛谷P1106 删数问题

删数本身是一个逆过程,不太符合人正常的认知。不妨考虑选数,即选出l-k个数字构成一个最小的整数。

结合小学数学的知识,高位数可以以一当十,所以只要较高位足够小,不管下面的数据如何挣扎变化 ,对于影响这个数的大小来说无济于事,换句话说就是高位决定整数的大小。
用更像中学数学的话来说,这个问题的求解想法,就是从高到低地选取每一位的时候,优先选择最小的数。每一步选择都是最小的,那么选到最后也必定是一个最小的数。

每一步都必须选最小。这就是我们所说的对步骤的贪心法。这个题目也是非常典型了。

贪心的证明是显然的,只是在证明过程当中,注意说明选第一个最小值,从而不会更坏。这样可以为后面选出更好的结果作铺垫。

注意几个边界情况:即

  1. 前导0
  2. 全是0
#include <bits/stdc++.h>
using namespace std;
int s[260], ans[260], k;
int main()
{
//清洗字符串,转化成int数组,同时得到数组大小
    string tmp;
    cin >> tmp;
    int l = tmp.size();
    for (int i = 0; i < l; i++)
        if (!isdigit(tmp[i])) tmp.erase(i--, 1), l--;
    for (int i = 0; i < l; i++)
        s[i] = tmp[i]-'0';

//贪心
    cin >> k; k = l - k;//确定选数的位数
    fill_n(ans, 260, 10);//初始化,任意个位数必然比10小(废话嘛
    int ti = -1;//目前扩展到的位置,ti及此前的元素已经不可选(给先前的贪心买单,尽管利益仍然是最大化)
    for (int i = 0; i < k; i++)
        for (int j = ti+1; j <= l-k+i; j++)//这个循环保证了选完这个之后,后面必然还能凑出完整的k位数
            if (s[j] < ans[i])//只需要当前位最小
                ans[i] = s[j], ti = j;

//输出
    int i = 0;
    while (ans[i] == 0) i++;//前导零
    if (i == k) cout << 0;//防止全是0
    while (i < k) cout << ans[i++];//正常模式
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值