湊平方數
把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 }
計算一下時間復雜度,很重要!如果很大很大,就建議直接放棄,換種思路!
正確題解(一維搜索,可以有效降低時間復雜度,因為在一維數組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; }
【正確答案:300】