大致的思路:
第一种: 比较暴力的思路就是弄出全排列。
然后再依次的枚举出 a,b,c。最后判断符不符合条件。
第二种就是 既然已经知道n了。那么把c乘过来。这样的话直接枚举 a和c 剩下的b可以直接求得。
最后再检查一下b满足不满足条件。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n;
int ans=0;
bool st[20],backup[20];
bool check(int a,int c)//检查b是不是满足条件
{
long long b=n*(long long)c-a*c;
if(!a||!b||!c) return false;
memcpy(backup,st,sizeof(st));
while(b)
{
int x=b%10;
b/=10;
if(!x||backup[x]) return false;
//如果b的数中有0,或者b中的数已经使用过。
backup[x]=true;
}
for(int i=1;i<=9;i++)//看9个数是不是都用了
{
if(!backup[i])
return false;
}
return true;
}
void dfs_c(int u,int a,int c)//已经用了多少个数字 a是多少 b是多少
{
if(u>9) return;
if(check(a,c)) ans++;
for(int i=1;i<=9;i++)
{
if(!st[i])
{
st[i]=true;
dfs_c(u+1,a,c*10+i);
st[i]=false;
}
}
}
void dfs_a(int u,int a)
{
if(a>=n) return;
if(a) dfs_c(u,a,0);
for(int i=1;i<=9;i++)
{
if(!st[i])
{
st[i]=true;
dfs_a(u+1,a*10+i);
st[i]=false;
}
}
}
int main(void)
{
cin>>n;
dfs_a(0,0);
//已经用了多少个数字
//a的值是多少。
cout<<ans<<endl;
return 0;
}
评论区大神的思路:
关键解析:
我们还需要分析一下如何写代码。所以我们现在枚举的方式就变成了先枚举a,然后对于每一个枚举的a来说,我们再去枚举c,那么对于每一个枚举
的c来说,a和c已经确定了,那么b也就确定了,就可以进行一个check的判断。虽然这里的话是做了一个很大的一个优化,但是代码写起来还是比较
复杂的。我们先写一个dfs_a函数,先dfs一下a,它其实是一个排列对吧,枚举一个排列,1,2,3,4…然后在dfs_a的内部,在每一个叶子节点的时
候,每一个叶子节点的地方,(因为每一个叶子就代表每一个a的可能成立的方案),那么在a的每一个叶子节点的地方,我们都需要再枚举一下c,
也就是我们要把a的每一个节点扩展成一个搜索树(即在a的每一个叶节点的时候dfs一下c),叶子上的每一棵树都是对c的搜索,因此我们这里其实
是dfs的一个嵌套关系,(即在一个dfs的过程中,把它的叶节点再dfs一下) 所以我们需要在dfs搜索a的时候在a的叶节点的基础上搜索一下对应的
c是多少,那搜完c之后的话我们再去判断一下b就可以了,也就是在c的每一个叶子节点上判断一下b就可以了。所以整个树的话会比较复杂一些。
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=10;
int had_use[N],ever[N];
int ans=0;
int n;
bool check(int a,int c)
{
long long int b=n*(long long)c-a*c;//把公式整理一下,然后先把b计算出来
if(!a||!b||!c)return false;
memcpy(ever,had_use,sizeof had_use);//因为我们要对这个判断是否出现的数组进行修改,但是原数组又不能变化,所以我们
//额外开一个数组进行使用,这样就可以达到判断且不会改变原数组的目的
while(b)
{
int t=b%10;//取它的每一位,用来更新一下用过的数字
b/=10;//删掉这个已经被选中的数
if(!t||ever[t])return false;
ever[t]=1;
}
for(int i=1;i<=9;i++)//遍历一下,判断每个数
if(!ever[i])
return false;
return true;
}
void dfs_c(int x,int a,int c)//x表示我们已经用了多少个数字
{
if(x>=10)return;//如果我们把10个数字都用了的话,那就直接return了
if(check(a,c))ans++;//如果满足要求,那我们判断一下a,c是否符合题目要求,如果符合,那么答案++
for(int i=1;i<=9;i++)//否则的话我们把c从1到9全部枚举一遍
if(!had_use[i])
{
had_use[i]=1;
dfs_c(x+1,a,c*10+i);//如果这个数没用过,那么我们就把它放在c的后面,继续dfs下一层
had_use[i]=0;
}
}
void dfs_a(int x,int a)
{
if(a>=n)return;
if(a)dfs_c(x,a,0);//如果说a是满足情况的,那么我们就枚举一下c,后面那个0表示c的大小
for(int i=1;i<=9;i++)//枚举一下当前这个位置可以用哪些数字
if(!had_use[i])
{
had_use[i]=1;
dfs_a(x+1,a*10+i); //如果这个数没有被用过,那么我们就加上它,并且dfs下一层
had_use[i]=0;//恢复现场,回溯一下
}
}
int main()
{
scanf("%d",&n);
dfs_a(0,0);//第一个0表示我们已经用了多少个数字,后面那个0表示我们当前的a是多少
printf("%d",ans);
return 0;
}
原文章链接: https://www.acwing.com/solution/content/38879/