代码改变世界

高精度整数去位取最小问题

2012-04-13 11:43  youxin  阅读(931)  评论(0编辑  收藏  举报

Description

键盘输入一个高精度的正整数N,去掉其中任意M个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的N和M寻找一种方案使得剩下的数字组成的新数最小。输出组成的新的正整数。(不超过240位) 

输入数据均不需判错。 

如果去掉了某几个位后得到的新整数开头为0,保留0。

Input

 

本题有多组测试数据,每组测试数据占一行。 

一个高精度正整数N(N不超过240位)一个正整数M。(M为不大于N的长度的正整数) 

N,M由一个空格分开。

Output

 

新的正整数,每组数据的输出占一行。不要多余的空白.

Sample Input

 

456547 1 456547 2 456547 3 7773359 2 103 1

 Sample Output

 45547 4547 447 73359 03

本题可以贪心算法快速解决。

数据结构设计: 对于高精度整数,可以将其存储为字符串格式。

问题分析: 在位数固定前提下,让高位的数字尽量小。其值就较小。依据贪心策略可以解决这个问题。

如何根据贪心来删除数字呢?总目标是删除高位较大的数字,具体地相邻两位比较,若高位比地位大则删除高位.

但是看下面的特殊情况:

n3="1 2 3 4 5 6 7" s=3

经过对n3相邻位进行比较,一个数字也没删除,这就要将后3位删除。当然还有可以在相邻比较的过程中删除的位数小于s,也要进行相似的操作。

算法设计:

  根据以上分析,算法注意由4部分组成:初始化,相邻数字比较(必要时删除),处理比较过程中删除位数不够s位情况和结果输出。

其中删除字符的实现方法很多:如

1.物理的进行字符删除,就是用后面的字符覆盖已删除的字符,字符串的长度改变,这样可能会有较多的字符移动操作,算法效率不高。

2.可以利用数字记录字符的存在状态,元素值为“1”表示对应的数值存在,0表示不存在。 但这样做前后数字的比较过程和最后的输出过程相对复杂些。

3,利用一个数组,来记录为删除字符的下标。删除值时对应数组的下标删除。

 

 

用C++的string类型很简单。代码如下:

 

#include<iostream>
#include<string>
using namespace std;

string greedy(string &str,int n)
{
     bool del;
     
     for(int i=n;i>0;i--) //这里为什么从n范围是从n到1,而不是从1到n,是为后面代码简化.
     {
         del=false;
         for(string::iterator it=str.begin();it!=str.end()-1;it++)
         {
             if(*it>*(it+1))
             {
                 str.erase(it);
                 del=true;
                 break; //为什么要跳出
             }

         }//end for
         //如果所有数字递增,则删除最后几个数字直接返回

              if(!del)
         {
             str.erase(str.end()-i,str.end());
             break;
        
         }
         
     }
         
     return str;
}
int main()
{
    string str;
    int n;
    cin>>str;
    cin>>n;
    cout<<greedy(str,n)<<endl;
    return 0;
}
         

 以1 2 4 3 为例,S=3;

最开始i=3; 进入里面的for循环后删除了4,退出for,变成了123

 i=2; del=false;for循环没有元素删除,!del为真,表示此时是按照从小到大排列的,从后面删除i个元素.2 ,3变成1.

结果为1.

 

删除数组中第i个字符:

/*删除数组a【】的第k个字符  数组名不能用delete,c++的关键字*/

void
del(char *a,int k) { while(a[k]!='\0') { a[k]=a[k+1]; k++; } } /*删除数组a【】从b起的k个字符 */ void del(char *a,int b,int k) { int i; for(i=b;i<=strlen(a)-k;i++) a[i]=a[i+k]; }

 

 较简单的c算法:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void find()
{
    char N[200];
    int s;
    int i=0,j;
    printf("input the number:");
    scanf("%s",N);
    printf("\ninput times:");
    scanf("%d",&s);
    while(s>0) /*循环减s次*/
    {

      i=0;/*每次删除后重头开始*/
      while(i<strlen(N) && N[i]<=N[i+1])
i++;/*算法核心*/ for(j=i;j<strlen(N);j++)N[j]=N[j+1];/*移位将删除的覆盖*/ s--; } printf("%s",N); } int main() { find(); system("pause"); }

 

 参考这里