hdu 3183

Problem Description
Kiki likes traveling. One day she finds a magic lamp, unfortunately the genie in the lamp is not so kind. Kiki must answer a question, and then the genie will realize one of her dreams.
The question is: give you an integer, you are allowed to delete exactly m digits. The left digits will form a new integer. You should make it minimum.
You are not allowed to change the order of the digits. Now can you help Kiki to realize her dream?
 

Input
There are several test cases. Each test case will contain an integer you are given (which may at most contains 1000 digits.) and the integer m (if the integer contains n digits, m will not bigger then n). The given integer will not contain leading zero.
 

Output
For each case, output the minimum result you can get in one line. If the result contains leading zero, ignore it.
 

Sample Input

178543 4
1000001 1
100001 2
12345 2
54321 2

 

Sample Output

13
1
0
123
321
题意:给出一个没有前导0的字符串  求删除k个数后最小的数

分析: 首先判断0的个数 如果有0 看0之前的非0数是否比k大 如果不比k大 优先考虑去除这些字符 循环此操作直到 0之前的非0数比k大或者没有0为止

如果字符串中的非0数不比 k 大 输出0   然后就是判断顺序递增与不递增的情况  递增的话就是去掉后面几位  非递增的话就是去掉前面的逆序数

#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int oo = 0x3f3f3f3f;
const int maxn = 1e6+7;
const int mod = 1e9+7;
typedef long long LL;
char str[20000], s[20000];
int vis[30], sign[20000];
int main()
{
    int i, m, k, j, a, id, cnt, last, g;
    ///last 去除0之前的数后现在的位置 g有多少个非0数
    while(scanf("%s %d", str, &m)!=EOF)
    {
        g = 0;
        memset(vis, 0, sizeof(vis));///标记字符串中数字的次数
        memset(sign, 0, sizeof(sign));///标记该位置的字符是否被去除
        for(i = 0; str[i] != ''; i++)
        {
            vis[str[i]-'0']++;
            if(str[i] != '0') g++;
        }

        int len = strlen(str);last = 0;
        if(m == len || g <= m)
        {
            printf("0
");
            continue;
        }
        if(vis[0] > 0)
        {
            while(1)///循环去除0之前所有能去除的数字以及0
            {
                cnt = 0;
                for(i = last; i < len; i++)
                {
                    if(str[i] == '0')
                    {
                        id = i;
                        break;
                    }
                    cnt++;
                }
                if(cnt > m) break;
                for(i = last; i < id; i++)
                    vis[str[i]-'0']--;
                m -= cnt;
                while(str[id] == '0' && id < len)
                {
                    vis[0] --;
                    id++;
                }
                last = id;
                if(id == len || vis[0] == 0) break;
            }
        }
        ///去除非递增序列的数(逆序数)
        for(i = last; i < len; i++) 
        {
            for(j = i-1; j >= last; j--)
            {
                if(str[j] > str[i] && sign[j] == 0)
                {
                    sign[j] = 1;
                    vis[str[j]-'0']--;
                    m--;
                }
                if(m == 0)break;
            }
            if(m == 0)break;
        }

        k = 0;
        if(m > 0) ///去除递增序列的后m个未被标记的数字
        {
            for(i = len-1; i >= last; i--)
            {
                if(vis[str[i]-'0'])
                {
                    vis[str[i]-'0']--;
                    m--;
                }
                if(m == 0)break;
            }
            //if(m == 0)break;
        }

        for(i = len-1; i >= 0; i--)///求最小所以大的数字要尽量放后面
        {
            a = str[i]-'0';
            if(vis[a] > 0)
            {
                s[k++] = a+'0';
                vis[a]--;
            }
        }
        k--;
        ///s数组为删除之后的最小数(需要倒序输出)
        while(s[k]=='0' && k > 0) k--;
        for(i = k; i >= 0; i--)
            printf("%c", s[i]);
        if(k == -1) printf("0");
        printf("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/PersistFaith/p/4964766.html