ACM 竞赛第六题(用时4小时) (2011-3-9 10:04)

题目要求:

输入一个T,则T线跟进,紧接着输入一个数num(10<num<10的1000次),保证输入不会有0,寻找一个最小的比num大的数

数的要求是:num每一位的乘积和这个数的每一位的乘积一样大。

样例输入:

3

12

19

222

样例输出

21

33

241

 

普通思路——穷举:无奈10的1000次太大,根本没办法举得尽;

优化思路——拆分:从个位到最高位每两位做,不行就做三位,但是当不能被64位整形所替代的数字也是没办法的,而且即使可以,也必定超时!

最终思路——记录、查找、排序:取出当前的数和数组里的数一一做过来,只要找到,替换这个数和数组的数所指的下标的数,然后最高位不变,后面的数排序处理。最后跳到主函数判断有没有做过交换,如果没有,则在前面输出1接着输出这个数,否则就直接输出这个数。注:(这个数组时用来记录不同的数字的下标,初始值全部是-1,当一个数和前面的数全部不符合要求的时候,就把这个数放到数组里)

 

代码:(建议理解了思路之后看代码,不然会一头雾水)

#include<stdio.h>
#include<string.h>
char a[1005];//由于是超大数,只能用数组来表示,字符变数字只需-48即可
int flag,len,link[10],num;
void start(){
 int i;
 for(i=0;i<10;i++)
  link[i]=-1;
 flag=0; 
}
int find2(int n,int m){
 int i;
 for(i=n*10+m+1;i<100;i++){
  if((i%10)*(i/10)==n*m){
   return i;
  }
 }
 return 0;
}
void find(){
 int i,j,min,minj=-1,tempi,tempj,tempk;
 char temp;
 start();//初始化数组和flag
 for(i=len-1;i>=0;i--){
  if(i==len-1){//如果是第一个,把数放到link数组里 
   link[a[i]-48]=i;
  }else{ //否则,从1到10判断link里有没有这个数,如果有则找符合要求的数(片段) find2(int n, int m)
   min=101;
   for(j=1;j<10;j++){
    if(link[j]>0){
     num=find2(a[i]-48,j);
     if(num>0 && num<100){
      if(num<min){
       min=num;
       minj=link[j];
      }
      flag=1;
     }
    } 
   }
   if(flag){//如果找到这个数(片段)
    a[i]=min/10+48;
    a[minj]=min%10+48;//就把这个数替换原来的两个数字 
    for(tempi=i+1;tempi<len-1;tempi++){//最高位不变,剩下的数排序保证数最小
     tempk=tempi;
     for(tempj=tempi+1;tempj<len;tempj++){
      if(a[tempk]>a[tempj])
       tempk=tempj;
     }
     if(tempk!=tempi){
      temp=a[tempi];a[tempi]=a[tempk];a[tempk]=temp;
     }
    }
    return ;
   }else{//如果找不到这个数(片段),就把当前的数字放到link[]数组里
    link[(int)a[i]-48]=i;
   }
  } 
 } 
}
int main()
{
 int t,i,j,k,temp;
 scanf("%d",&t);
 getchar();
 while(t--){
  gets(a);
  len=strlen(a);
  find(); //查找这个数
  if(flag){//找到了,直接输出
   puts(a);
  }else{//找不到,前面加个1排序输出
        for(i=0;i<len;i++){
         k=i;
         for(j=i+1;j<len;j++){
          if(a[k]>a[j])
           k=j;
         }
         if(k!=i){
          temp=a[i];a[i]=a[k];a[k]=temp;
         }
        }  
       printf("1%s\n",a);
  }
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值