第七屆藍橋杯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\n",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\n",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\n",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十萬\n",i1,i2,i3,i4,i5,Time/(ll)100000);
213                     }
214                 }
215             }
216         }
217     }
218 
219     printf("總ans有:ans=%d\n",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','\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\n",cnt);
    ans=0;
    dfs(1,"",cnt);
    printf("%d\n",ans);

    return 0;
}
View Code

 

【正確答案:300】

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM