一、题目
由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如:
210 x 6 = 1260
8 x 473 = 3784
27 x 81 = 2187都符合要求。
如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式。
请填写该数字,通过浏览器提交答案,不要填写多余内容(例如:列出所有算式)。
二、思路
暴力枚举所有四位数,先把乘积的数字中会有重复数位的排除掉,然后记录每个数位,再来求乘数和被乘数。之后在求乘数和被乘数的时候也要判重复,把数位会重复的数字排除掉。
需要注意的是,只有0123456789十个数字,要求的是一个四位数,那么最小的是1023,最大的是9876,作为循环范围可以缩小范围。
还有一个需要注意的是,我们在求乘数或被乘数的时候可以用这个乘积的平方根作为最大限界。
接下来要对乘数和被乘数进行排重:将出现过的数字标记为1,所以当标记为0或者2的时候,跳出循环。
三、题解
#include <iostream> #include <algorithm> #include <cmath> using namespace std; int main() { int a,b,c,d; int m,n; int flag; int ans=0; int num[11]; for (int i=1023;i<=9876;i++) { a=i%10;//个位 b=i/10%10;//十位 c=i/100%10;//百位 d=i/1000;//千位 if(a==b || a==c || a==d || b==c || b==d || c==d) //如果数位有重复的就排除掉 { continue; } for (int j=2;j<sqrt(i);j++) //用乘积的平方根作为最大限界 { memset(num,0, sizeof(num)); num[a]=1; num[b]=1; num[c]=1; num[d]=1; //代表乘积的数字的每个数位已经出现过,标记为1 if(i%j==0) { flag=1; m=j; n=i/j; while(m) { if(num[m%10]==1) num[m%10]++; else if (num[m%10]==0 || num[m%10]==2) { flag=0; break; } m=m/10; } if(!flag) continue; while(n) { if(num[n%10]==1) num[n%10]++; else if (num[n%10]==0 || num[n%10]==2) { flag=0; break; } n=n/10; } if(flag) { cout << j << "*" << i/j << "=" << i << endl; ans++; } } } } cout << ans << endl; return 0; }
四、结果
6*201=1206
6*210=1260
21*60=1260
15*93=1395
35*41=1435
3*501=1503
3*510=1530
30*51=1530
21*87=1827
27*81=2187
9*351=3159
8*473=3784
12Process finished with exit code 0
故答案是12种方案。但是这种方法速度血妈慢,待优化