Description
ACM小组喜欢上了一个无聊的游戏,游戏的过程是输入一个正整数n,去掉n的任意S个数字后,把剩下的数字看作是一个新的整数(去除前导零)。对给定的N和S,寻找一种删数规则使得剩下的数字组成的新数(排列顺序不变)最小。希望你也可以加入这个游戏,编写程序来解决这个问题。
Input
输入包含若干组数据,每组数据一行,为用空格分隔的两个正整数n(2<=length( n )<=2000,length(n)为n的位数)和S(0<S<length(n))。
读入以EOF结束。
Output
对于每个输入数据,输出删除S个数后剩下最小的新数(不要输出前导0)。
Sample Input
5412364 4
Sample Output
123
HINT
#include <stdio.h>
#include <string.h>
#define MIN(a,b) ((a)<(b)?(a):(b))
#define N 2005
char s[N];
int d[N],top;
int main()
{
int i,j,k,len,cnt,f;
int t,min,max,mid;
while(~scanf("%s%d",&s[1],&k))
{
s[0]=-1,top=0;
d[top++]=0;
len=strlen(s);
for(i=1,cnt=0;cnt<k&&i<=len;)
{
if(top==1||s[i]>=s[d[top-1]])
{
d[top++]=i++;
continue;
}
else
{
min=0,max=top-1;
while(min+1!=max)
{
mid=(min+max)>>1;
if(s[i]<s[d[min]]) max=mid;
else min=mid;
}
t=MIN(k-cnt,top-max);
top-=t,cnt+=t;
}
}
f=1;
for(j=1;j<top&&s[d[j]]=='0';j++);
for(;j<top;j++) printf("%c",s[d[j]]),f=0;
if(f) for(;i<len&&s[i]=='0';i++);
for(;i<len;i++) printf("%c",s[i]),f=0;
if(f) printf("0");
printf("\n");
}
return 0;
}
经典贪心算法题。题目大意,给定一个整数N(位数最多2000)和整数k,在N中删除k个数使得剩下的数组成的整数最小。需要注意的是结果不要输出前导0。
贪心策略为:从高位到低位扫描,若存在递减区间,则将高位删除以消除递减区间,否则从低位删。具体操作时,可以设一个栈来保存从高位起还没删的数。不难发现最后的结果一定是一个不下降序列,由此可以想到用二分来优化。(待研究)