寒假作业
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
(如果显示不出来,可以参见【图1.jpg】)
每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
这一题我们很快知道要用全排列,但是全排列一旦超过12就会计算得非常慢,这一题要求只提交一个整数,只是写出全排列的话一分钟也是可以出结果的,但是我们可以更快。
但是我的题目也包含了“递归全排列”,是因为打算一起记录一下递归全排列如何写,会的小伙伴可以跳过哈
首先简述一下递归写全排列的过程,假设要做1,2,3的全排列,那么一般时先写出1开头的所有排列,再写出2开头的,以此类推,这个过程就是拿第一位到最后一位的数不断与第一位交换,再递归。
如果只有一位数字全排列,那么我们只要输出它本身即可,这便确定了边界。
程序如下:
#include<iostream>
#include<cstdio>
using namespace std;
//这个函数的名字是因为写题要用DFS,故而起了这个名,不用在意
void dfs(int a[],int p,int q)//p表示第一位的下标,q表示最后一位的下标
{
if(p==q)//边界
{
int i;
for(i=0;i<=q;i++)
printf("%d",a[i]);
printf("\n");
}
for( int i=p;i<=q;i++)
{
int temp=a[i];//依次交换
a[i]=a[p];
a[p]=temp;
dfs(a,p+1,q);//记得要交换回来
temp=a[i];
a[i]=a[p];
a[p]=temp;
}
}
int main()
{
int a[3]={1,2,3};
dfs(a,0,2);
}
不过这个程序有个问题,就是不能按照字典序输出,这个时候可以在输出前用sort(),鉴于待会的题目不需要用到字典序的全排列,这里先不讲啦。
回到题目,我们可以在下一次调用DFS前增加条件,这样就可以大大的节省时间了。
程序如下:
//寒假作业
#include<iostream>
using namespace std;
int a[13]={1,2,3,4,5,6,7,8,9,10,11,12,13};
int num=0;
bool cleck(int x)
{
if(a[0]+a[1]==a[2] &&
a[3]-a[4]==a[5] &&
a[6]*a[7]==a[8] &&
a[9]%a[10]==0 &&
a[9]/a[10]==a[11])//这里是为了避免直接用/会取整
return true;
return false;
}
void dfs(int x)
{
int i;
if(x==13)
{
if(cleck(x))
num++;
}
else
{
for(i=x;i<13;++i)
{
int temp=a[i];
a[i]=a[x];
a[x]=temp;
if((x==2&&a[0]+a[1]!=a[2])||(x==5&&a[3]-a[4]!=a[5]))//增加的就在这里
{
temp=a[i];//记得要变回去
a[i]=a[x];
a[x]=temp;
continue;
}
dfs(x+1);
temp=a[i];
a[i]=a[x];
a[x]=temp;
}
}
}
int main()
{
int x;
dfs(0);
cout<<num;
return 0;
}
其实可以看得出来,这个程序和我们一开始的递归全排列相比其实只是增加了一些程序语句,虽然挺简单的,但是我迷惑了超级久呢,果然打好基础是非常重要的QAQ。