zoukankan      html  css  js  c++  java
  • 第七届蓝桥杯C/C++程序设计本科B组决赛 ——凑平方数(填空题)


    凑平方数

    把0~9这10个数字,分成多个组,每个组恰好是一个平方数,这是能够办到的。
    比如:0, 36, 5948721

    再比如:
    1098524736
    1, 25, 6390784
    0, 4, 289, 15376
    等等...

    注意,0可以作为独立的数字,但不能作为多位数字的开始。
    分组时,必须用完所有的数字,不能重复,不能遗漏。

    如果不计较小组内数据的先后顺序,请问有多少种不同的分组方案?

    注意:需要提交的是一个整数,不要填写多余内容。


    错误题解(答案错误原因未知、暴力五重for循环——超时,优化再优化超时!)——可供借鉴!

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <iostream>
      4 #include <algorithm>
      5 #include <queue>
      6 #include <stack>
      7 #include <vector>
      8 #include<math.h>
      9 #include <string.h>
     10 #include<set>
     11 using namespace std;
     12 #define inf 0x3f3f3f3f
     13 #define maxn 10000000
     14 const double pi=acos(-1.0);
     15 #define ll long long
     16 #define N 100008
     17 using namespace std;
     18 vector<ll>a;
     19 int getlen(ll x){// 返回x的数字位数
     20     return (int)log10(x*1.0)+1;
     21 }
     22 int cmp1(ll x){   //cmp1()表示传入的1个数是否没有重复数码
     23     int arr[10]={0};
     24     while(x>0){
     25         arr[x%10]++;x/=10;
     26     }
     27     for(int i=0;i<=9;i++)
     28         if(arr[i]>1)return 0;
     29     return 1;
     30 }
     31 int cmp2(ll x,ll y){ //cmp2--5()表示传入的2--5个数是否可以不重不漏地构成十位数码
     32     if(getlen(x)+getlen(y)>10)
     33         return 3;
     34     int arr[10]={0};
     35     while(x>0){
     36         arr[x%10]++;x/=10;
     37     }
     38     while(y>0){
     39         arr[y%10]++;y/=10;
     40     }
     41     for(int i=0;i<=9;i++){
     42        if(arr[i]>1)return 0;
     43        else if(arr[i]==0)return 2;//缺省时
     44     }
     45 
     46     return 1;
     47 
     48 }
     49 int cmp3(ll x,ll y,ll z){
     50     if(getlen(x)+getlen(y)+getlen(z)>10)
     51         return 3;
     52     int arr[10]={0};
     53     while(x>0){
     54         arr[x%10]++;x/=10;
     55     }
     56     while(y>0){
     57         arr[y%10]++;y/=10;
     58     }
     59      while(z>0){
     60         arr[z%10]++;z/=10;
     61     }
     62    for(int i=0;i<=9;i++){
     63        if(arr[i]>1)return 0;
     64        else if(arr[i]==0)return 2;//缺省时
     65     }
     66     return 1;
     67 }
     68 int cmp4(ll x,ll y,ll z,ll h){
     69     if(getlen(x)+getlen(y)+getlen(z)+getlen(h)>10)
     70         return 3;
     71     int arr[10]={0};
     72     while(x>0){
     73         arr[x%10]++;x/=10;
     74     }
     75     while(y>0){
     76         arr[y%10]++;y/=10;
     77     }
     78     while(z>0){
     79         arr[z%10]++;z/=10;
     80     }
     81     while(h>0){
     82         arr[h%10]++;h/=10;
     83     }
     84     for(int i=0;i<=9;i++){
     85        if(arr[i]>1)return 0;
     86        else if(arr[i]==0)return 2;//缺省时
     87     }
     88     return 1;
     89 
     90 }
     91 int cmp5(ll x,ll y,ll z,ll h,ll t){//表示传入的五个数是否可以不重不漏地构成十位数码
     92     if(getlen(x)+getlen(y)+getlen(z)+getlen(h)+getlen(t)>10)
     93         return 3;
     94     int arr[10]={0};
     95     while(x>0){
     96         arr[x%10]++;x/=10;
     97     }
     98     while(y>0){
     99         arr[y%10]++;y/=10;
    100     }
    101     while(z>0){
    102         arr[z%10]++;z/=10;
    103     }
    104     while(h>0){
    105         arr[h%10]++;h/=10;
    106     }
    107     while(t>0){
    108         arr[t%10]++;t/=10;
    109     }
    110     for(int i=0;i<=9;i++){
    111        if(arr[i]>1)return 0;
    112        else if(arr[i]==0)return 2;//缺省时
    113     }
    114     return 1;
    115 
    116 }
    117 
    118 int main(){
    119 
    120     ll maxx=9876543210;//确定上限
    121     int cnt=0;
    122     a.clear();
    123     for(ll i=0;i<=100000;i++){//筛选出制定范围内的所有平方数
    124         if(i*i>maxx)break;
    125         if(cmp1(i*i)==1)////将自身数码不重复的平方数存入a中
    126             a.push_back(i*i);
    127     }
    128 
    129     cnt=a.size();
    130     printf("总的平方数==%d %lld
    ",cnt,a[cnt-1]);//611 9814072356
    131 
    132     int ans=0;
    133     for(int i=cnt-1;i>=0;i--){///把后面的十位数平方数全部删除掉
    134         if(getlen(a[i])==10){
    135             ans++;a.pop_back();
    136         }
    137         else
    138             break;
    139     }
    140     cnt=a.size();
    141     printf("10位的平方数有ans=%d %d %lld
    ",ans,cnt,a[cnt-1]);//87,524
    142     /*由于接下来只剩1--9位的平方数了,可以进行两两枚举、三三枚举、四四五五地枚举;
    143     原先就是如下写的————
    144     for(int i1=0;i1<cnt;i1++){
    145         for(int i2=i1+1;i2<cnt;i2++){
    146             if(cmp2(a[i1],a[i2])==1)
    147                 ans++;
    148         }
    149     }
    150     for(int i1=0;i1<cnt;i1++){
    151         for(int i2=i1+1;i2<cnt;i2++){
    152             for(int i3=i2+1;i3<cnt;i3++){
    153                 if(cmp3(a[i1],a[i2],a[i3])==1)
    154                     ans++;
    155             }
    156         }
    157     }
    158     for(int i1=0;i1<cnt;i1++){
    159         for(int i2=i1+1;i2<cnt;i2++){
    160             for(int i3=i2+1;i3<cnt;i3++){
    161                 for(int i4=i3+1;i4<cnt;i4++){
    162                     if(cmp4(a[i1],a[i2],a[i3],a[i4])==1)
    163                         ans++;
    164                 }
    165             }
    166         }
    167     }
    168     for(int i1=0;i1<cnt;i1++){
    169         for(int i2=i1+1;i2<cnt;i2++){
    170             for(int i3=i2+1;i3<cnt;i3++){
    171                 for(int i4=i3+1;i4<cnt;i4++){
    172                      for(int i5=i4+1;i5<cnt;i5++){
    173                         if(cmp5(a[i1],a[i2],a[i3],a[i4],a[i5])==1)
    174                             ans++;
    175                     }
    176                 }
    177             }
    178         }
    179     }
    180 
    181     */
    182     //后来发现这其中有大量重复计算,在上面两两枚举中,若一对数有冲突仍会进行往下跑循环,
    183     //再细想,发现三重循环实际上包含了两重循环,四重含三重和两重,五重......
    184     //所以可以进行简单优化,continue,并且有了下面的四合一程序
    185     int k;
    186     printf("ans有:ans=%d
    ",ans);
    187     ll Time=0;
    188     for(int i1=0;i1<cnt;i1++){
    189         for(int i2=i1+1;i2<cnt;i2++){
    190                 if(k=cmp2(a[i1],a[i2]),k==1)
    191                     ans++;
    192                 if(k==0||k==1)//k=0有重复或者k=1找到答案,k==2表示缺省(可以向下搜),k==3表示总位数超10——break
    193                     continue;
    194                 if(k==3)break;
    195             for(int i3=i2+1;i3<cnt;i3++){
    196                     if(k=cmp3(a[i1],a[i2],a[i3]),k==1)
    197                         ans++;
    198                     if(k==0||k==1)//有重复或者已经全部使用过了
    199                         continue;
    200                     if(k==3)break;
    201                 for(int i4=i3+1;i4<cnt;i4++){
    202                         if(k=cmp4(a[i1],a[i2],a[i3],a[i4]),k==1)
    203                             ans++;
    204                         if(k==0||k==1)//有重复或者已经全部使用过了
    205                             continue;
    206                         if(k==3)break;
    207                     for(int i5=i4+1;i5<cnt;i5++){
    208                         if(k=cmp5(a[i1],a[i2],a[i3],a[i4],a[i5]),k==1)
    209                             ans++;
    210                          if(k==3)break;
    211                         Time++;
    212                         if(Time%(ll)100000==0)printf("%3d,%3d,%3d,%3d,%3d, Time=%5lld十万
    ",i1,i2,i3,i4,i5,Time/(ll)100000);
    213                     }
    214                 }
    215             }
    216         }
    217     }
    218 
    219     printf("总ans有:ans=%d
    ",ans);
    220     return 0;
    221 }
    View Code

    计算一下时间复杂度,很重要!如果很大很大,就建议直接放弃,换种思路!


    正确题解(一维搜索,可以有效降低时间复杂度,因为在一维数组a[]中,元素是递增的--元素的长度就是非递减的,一旦某一个因为长度超出后不合适——后续的都不合适了)。

    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <vector>
    #include<math.h>
    #include <string.h>
    #include<set>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define maxn 10000000
    const double pi=acos(-1.0);
    #define ll long long
    #define N 10008
    using namespace std;
    ll a[N];
    
    int check(string num){//判断字符串num是否重复
        int arr[10]={0};
        int len=num.length();
        for(int i=0;i<len;i++){
            int t=num[i]-'0';
            arr[t]++;
            if(arr[t]>1)return 0;
        }
        return 1;
    }
    string turn(ll num){//将num转化成字符串进行输出
        string s;
        if(num==0)s+="0";
        while(num>0){
            char ch[]={num%10+'0',''};//临时字符串,用于string的插入
            s.insert(0,ch);
            num/=10;
        }
        return s;
    }
    int ans;//在a[]数组中进行一维搜索,每次选取step的位置,然后再往后选取一位合适的
    void dfs(int step,string s,int cnt){
    
        if(s.length()>10||check(s)==0)return ;
    
        if(s.length()==10&&check(s)==1){
            ans++;
            return ;
        }
        for(int i=step;i<=cnt;i++){
            dfs(i+1,s+turn(a[i]),cnt);
        }
    
    }
    int main(){
    
        ll maxx=9876543210;
        int cnt=0;
        for(ll i=0;i<=100000;i++){//生成完全平方数表,共cnt个
            if(i*i<=maxx){
                if(check(turn(i*i)))
                        a[++cnt]=i*i;
            }
            else break;
        }
        printf("完全平方数cnt=%d
    ",cnt);
        ans=0;
        dfs(1,"",cnt);
        printf("%d
    ",ans);
    
        return 0;
    }
    View Code

    【正确答案:300】

  • 相关阅读:
    jQuery 小特效【文本框折叠隐藏,展开显示】【下拉菜单】【颜色渐变】【弹窗+遮罩】
    jQuery 【事件】【dom 操作】
    jQuery 【选择器】【动画】
    LINQ 小项目【组合查询、分页】
    LINQ 【高级查询】
    LINQ 【增、删、改、查】数据绑定
    WebFrom 【文件上传】
    【转】c# 字符串大小写混合转换
    【转】C#之继承
    类库,通用变量,is/as运算符,委托。
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/9041390.html
Copyright © 2011-2022 走看看