凑平方数
把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】