可绝对贪婪问题
Case1:键盘输入一个高精度的正整数n,去掉其中任意s个数字后剩下的数字按原左右次将组成一个新的正整数。对于给定的n和s,使得剩下的数字组成新数最小并输出。
问题分析:
在位数固定的前提下,让高位的数字尽量小,其值就越小,依据贪心策略就可以解决这个问题。但是数据的不同也会造成不同种情况的出现,例如 假设1,假设2,假设3
假设1:
n=“12435863” s=2(去掉两个数)
开始
第一次比较 “1 2 4 3 5 8 6”
1相对于2 在高位,但是数字小于低位的2, 所以不变
第二次比较“1 2 4 3 5 8 6”
2相对于4 在高位,但是数字小于低位的4 ,所以不变
第三次比较“1 2 4 3 5 8 6”
4相对于3 在高位,但是数字大于低位的4 ,所以4被移除。
第四次比较“1 2 3 5 8 6”
3相对于5 在高位,但是数字小于低位的5, 所以不变
第五次比较“1 2 3 5 8 6”
5相对于8 在高位,但是数字小于低位的8, 所以不变
第五次比较“1 2 3 5 8 6”
8相对于6 在高位,但是数字大于低位的8,所以8被移除。
最后输出 12356 为最小数
结束
因此,可得相邻数字只需要从前向后比较;
假设2:
n=“231183” s=3(去掉三个数)
开始
第一次比较 “2 3 1 1 8 3”
2相对于3 在高位,但是数字小于低位的3,所以不变
第二次比较“2 3 1 1 8 3”
即得“2 1 1 8 3”
3相对于1 在高位,但是数字大于低位的1,所以3被移除。
第三次比较“2 1 1 8 3”
2相对于1 在高位,但是数字大于低位的1,所以2被移除。
即得“ 1 1 8 3”
第四次比较“ 1 1 8 3”
1相对于1在高位,两者相等, 所以不变
第五次比较“ 1 1 8 3”
1相对于8在高位,但是数字小于低位的8, 所以不变
第六次比较“ 1 1 8 3”
8相对于1在高位,但是数字大于低位的1, 所以8被移除
即得“ 1 1 3”
最后输出 113 为最小数
结束
因此,可得当第i位与第i+1位比较,若删除第i位后,必须向前考虑第i-1位与第i+1位进行比较,才能保证结果的正确性。
假设3:
n=“123456” s=3(去掉三个数)
可以清楚的看到,相邻的数字比较都不用删除,这时要考虑将后三位删除,即为最小值为123
当然也还有另外一种可能
假设3-1
n="120083" s=3(去掉三个数)
3 比 0 大删除 即“1 0 0 8 3”
2比 0 大删除 即“ 0 0 8 3”
8比 3 大删除 即“ 0 0 3”
最小值3
由此,在n含有0时,当删除掉一些数字后,结果高位可能会出现数字0,直接输出这个数据不合理。应该将所有高位的0去除再输出。特别地还要考虑若结果串是0000时,不能将0都删除,而要保留一个“0”最后输出
因此,从以上假设来看,进行算法设计时,从具体到抽象的归纳一定要选取大量不同的实例充分了解和体会解决问题的过程,规律和各种不同情况,才能设计出正确的算法。
算法设计:
delete(char [],int b,int k){
int i;
for(i=b;i<length(n)-k;i++){
n[i]=n[i+k];
}
main(){
char n[100];
int s,i,j,j1,c,data [100],len;
cin>>n>>s;//n 为正整数,去除s个数字
len=length(n);
}
if(s>len){
cout<<"数据错误!";
return;
}
j1=0;
for(i=1;i<=s;i++){
{for(j=1;j<length(n);j=j+1)
{
if(n[j]>n[j+1]){ //贪心选择
delete(n,j,1);
}
if(j>j1){
data[i]=j+i; //记录删除数字的位置
}else{ //假设2向前删除
data[i]=data[i-1]-1;
}
j1=j;
break;
}
if(j>length(n)){
break;
}
for(i=i;i<=s;i++){
j=len-i+1;
delete(n,j,1);
data[i]=j;
} while(n[1]='0' && length(n)>1){
delete(n,1,1); //将字符串首的若干“0”去掉
cout<<n;
for(i=1;i<=s;i++){
cout<<data[i]<<'';
}
}
}
}
}
复制代码
综上所述:算法主要由四部分组成:初始化,相邻数字比较(必要时删除),处理比较过程中删除不够s位的情况和结果输出。