贪心算法



删数问题计蒜客 - T1851 

题意:就是给一个200位的正整数,然后给你k次删除一个数位上的数的机会,然后剩下的数字组成的数最小。

思路:贪心,因为高位数大小影响大,所以从高位进行遍历,如果发现前一位数字比后一位数字大即可删除。

  每一次删除数字,都只会影响到前面一个,所以每次删除之后,向前找符号条件,然后进行删除,否则停止,继续先后遍历;

  等遍历完整个数字串,就确定这个数字是一个递增序列,如果还有操作数,就从末尾删除。

易错点:高位开头的多余0,在最后输出的时候要去掉。

这里我用string存储,并且使用string的erase函数删除单个字符。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <map>
#include <cmath>

using namespace std;

int main()
{
    string dig;int k;
    cin>>dig>>k;

    int len = dig.length()-k;
    int up=0,down;
    //true For up
    bool flag = true;
    while(up<=(dig.length()-1)&&k){
        if(flag){
            if(dig[up]>dig[up+1]){
                dig.erase(up,1);
                //cout<<dig<<endl;
                k--;
                flag = false;
                down = up-1;
            }else up++;
        }else{
            while(down>=0&&dig[down]>dig[up]&&k) dig.erase(down,1),up = down,down = up-1,k--;
            flag = true;
        }
    }


    int st=0;
    while(st<len&&dig[st]=='0') st++;
    if(st<len) {
        for(int i=st;i<len;i++) cout<<dig[i];
        cout<<endl;
    }
    else puts("0");
    return 0;
}
View Code

 拓展思维:一开始读题,“剩下的数字按原左右次序将组成一个新的正整数。”,这句话以为意思是头与末尾交替取数,然后组成一个最小的数。

举例子:abcd-->adbc

我的思路(不一定正确,因为没时间验证,所以这里先提出来,有异议者欢迎一起讨论):

1.先算出结果长度len。

2.从末尾数起第len个数开始往前遍历找最小的数,作为目标子序列的头点。

3.从这个头节点数起第len-1个数往后找最小的数作为目标子序列的尾点。

4.接替寻找符合要求的点,跳出循环的条件有两个,一个就是找到最新的相邻的前后节点长度刚好达到目标长度,即没有可以删除的点了。第二就是找到的点的总数量刚好达到第一步len,跳出循环。



部分背包问题:



这里讲一个以前的经历:

当时做的都是图论、匹配、博弈等,然后0-1背包这种的确懂,但是动态规划不是很懂只是在会用的地步(记得当时会写数位dp)。

有一次遇到一个问题,当时第一想法就用了贪心,测试用例都过了,但就是一直wrong。

实在不懂,问了朋友才知道是背包问题。。。


原文地址:https://www.cnblogs.com/BugClearlove/p/13890520.html