94736 / 01528 = 62
分析:这个可以用暴力求解法,但是如何暴力,暴力到啥程度值得注意。若是单纯地枚举0~9的所有排列就显得太繁琐了。通过对题目中abcde/fghij = n进行分析,可以移项得到n*fghij=abcde,故而只需枚举fghij就可以算出abcde,然后判断是否所有数字都不相同即可。不仅简单,而且枚举量从10!=3628800降低到不到一万,而且只要abcde和fghij只要超过100000就可以终止枚举。好了,算法分析出来了,那么就要写代码了。写代码主要有两个问题,一是如何将枚举的数放入数组中,二是如何判断数组是否有重复的数。下面贴代码,有两个版本,可以进行一下比较它们对以上两个问题的解决策略。
第一种(繁琐版)
#include
#include
int judge(char s[])
{
for(int i=0;i<9;i++) //②
{
for(int j=i+1;j<10;j++)
{
if(s[i]==s[j])
return 0;
}
}
return 1;
}
int main()
{
int n,fg=1;
while(scanf("%d",&n)&&n!=0)
{
if(fg)
fg=0;
else printf("\n");
int flag=0;
char s[10]={0};
for(int i=1234;i<98765;i++)
{
int t=9;
int m=i;
while(m) //①
{
s[t--]=m%10;
m/=10;
}
int k=n*i;
if(k>=100000)
break;
else
{
int q=4;
while(k)
{
s[q--]=k%10;
k/=10;
}
//puts(s);
if(judge(s))
{
flag=1;
for(int j=0;j<10;j++)
{
if(j==5)
printf(" / ");
printf("%d",s[j]);
}
printf(" = %d\n",n);
}
}
}
if(!flag)
printf("There are no solutions for %d.\n",n);
}
return 0;
}
第二种(改进版)
#include
#include
using namespace std;
bool num[10];
char str[10];
bool check(int a,int b){
sprintf(str,"%05d%05d",a,b); // ①
memset(num,false,sizeof(num)); //②
for(int i=0;i<10;i++){
if(num[ str[i]-'0' ]) return false;
num[ str[i]-'0' ]=true;
}
return true;
}
int main(){
int n;
bool first=true;
while(scanf("%d",&n) && n){
bool ok=false;
if(first) first=false;
else printf("\n");
for(int i=1234;i<=98765;i++){
if(i%n==0){
if(check(i,i/n))
ok=true,printf("%05d / %05d = %d\n",i,i/n,n);
}
}
if(!ok) printf("There are no solutions for %d.\n",n);
}
return 0;
}
PS:①对于“如何将枚举的数放入数组中”这个问题,第一种方法是通过"取余相除过河拆桥”法将每一位的数一一放入数组中,而第二种方法却是通过函数sprintf(s,“%d”,x)实现的,简洁有效!
②关于“如何判断数组是否有重复的”这个问题,法一通过两个for语句简单排查,而法二则是通过构造一个对应的“记录数组”,(不合适应用于存在递归的函数中)先是将这个“记录数组”初始化为零,然后只要出现一个数,就将以这个数为下标的数组单元赋值为一,每次操作都先检查数组单元是否为一,若是,则有重复,否则就将其赋值为一
总结:即使采取暴力法求解问题,对问题进行一定的分析往往会让算法更加简洁、高效。另外,在枚举复杂对象之前,先尝试着枚举一些相对简单的内容,如整数、子串。