猴开森
学了两天第一次不看题解做出一道DFS题,至少看到自己的一点进步,也是很开心了,赶紧把题解写下来
(o゜▽゜)o☆[BINGO!]
Description
写一个程序要求当输入在整数范围内的一个整数R后, 计算机便会检查,在下式□处能否填上“+”、“-”或“×”号凑成相应等式。如能凑成,则印出所有这些等式的个数。注意,考虑符号的优先级。 1□2□3□4□5□6□7□8□9=R
Input
只有一行,就是一个整数R。
Output
只有一行,就是使等式成立的个数。
Sample Input
20
Sample Output
30
思路
这道题看到之后的初步思路就是枚举所有情况,正是这两天做学的DFS的应用 — 穷举(先探出整个一条路,对这一种情况进行判断,然后继续进行下一种情况的枚举),像这种穷举,普通的循环好像是很难写的(??)反正DFS是可以解决的
WA犯的错误
- 第一个错误曾经以各种形式犯过,希望以后再也不要这样了,一句一句调试找到的,血的教训:判断一条解是否成立的部分,按照我的方法,是将×后的数先乘到第一个数上,然后将×后的数赋0,这样就可以在之后的加法中直接求和了。但是!!!判断完一次后,我没有重新赋值,因为1-9的存放数组是全局变量,所以下一次的判断是用的被改变的数组进行的,答案当然是错的。总结就是:在使用东西前好好想想它们现在所处的状态,尤其是全局变量
- 刚开始加减法计算总和的时候,的方法是:首先sum = 1为初值,然后再根据+/-依次将2-9求和!!!但是我忽略了,按照上述的方法,1已经不一定是1了,很可能1是紧接着好多连×,所以sum = a[1] 才对
核心代码
void dfs(int cur)
{
if(cur==9)//8个空,1-8,9的时候说明已经试探出了一种解决方案了,这时才会判断是否可行
{
//判断这条解决方案是否成立,成立则total+1
return; //不论成不成立,这条解决方案处理完了,该下一条了,所以才return
}
for(int i = 1;i<=3;i++)//每个符号空都有3种情况(1+,2-,3*)
{
sign[cur] = i;//这个空试探赋值
dfs(cur+1); //为下一个空试探赋值
}
}
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int sign[10];
int a[11];
long long total;
long long r,sum;
void dfs(int cur)//cur从1开始
{
if(cur==9)
{
for(int i = 8;i>=1;i--)//先计算乘法
{
if(sign[i]==3)
{
a[i]*=a[i+1];
a[i+1] = 0;
}
}
sum = a[1];
for(int i = 1;i<=8;i++)//求和
{
if(sign[i] == 2) sum-=a[i+1];
else sum+=a[i+1];
}
for(int i = 1;i<=9;i++) a[i] = i;//之前没想到,每次检测是否成立的时候都将a数组更改后,下次要不重新初始化就做不出来了
if(sum==r) total++;
return;
}
for(int i = 1;i<=3;i++)
{
sign[cur] = i;
dfs(cur+1);
}
}
int main(void)
{
while(scanf("%lld",&r)!=EOF)
{
for(int i = 1;i<=9;i++) a[i] = i;
total = 0;
dfs(1);
printf("%lld\n",total);
}
return 0;
}