不正经模式:
父亲今天买了包火柴点烟(鬼知道他为什么不用打火机),闲来无事的我把父亲没有用的火柴取出来放在桌子上,开始摆弄起来。由于尺寸大了一点,1这个数字用两根竖着的火柴棒表示。(注意,这句话很重要)
举个例子:
额貌似不怎么形象,就这样好了。你只知道我因为摆弄火柴的时候《突发奇想》就出了一个题就行了。
正经模式:
废话不多说,你看见标题的时候是不是认为我在玩小孩子家家的儿戏?NONONO,小伙子你格局小了,既然我都说了火柴棍可以“这么玩”,那肯定就有它的独特之处。
这不是儿戏,而是我将要出的一道题,编程语言是C++。
现在假设桌子上有14根火柴棍,则可以拼出两种不同的等式:0+1=1和1+0=1,数字可能有些抽象,我画了个图示意一下:
0+1=1和1+0=1本质没有什么区别,我就不画0+1=1了。由图可知,火柴棍总数为2+2+6+2+2=14。
我直接说吧,在我的规定里,0由6根棍子组成,1由2根棍子组成,2由5根棍子组成,3由5根棍子组成,4由4根棍子组成,5由5根棍子组成,6由6根棍子组成,7由3根棍子组成,8由7根棍子组成,9由6根棍子组成。
另:内容也许很枯燥,但是坚持突破很酷!
发现规律了吗?只要拼的出来等式,它就一定会有2个及以上的组合。而最少的两个,其实就是加法交换律。
题目描述:
假如现在我手上有n根(n<=24)火柴棍,那么我能拼出多少个不同?+?=?的等式呢?
注意:
1.加号和等号各自需要两根火柴棍。
2.如果A≠B,则A+B=C与B+A=C视为不同的等式(A,B,C都大于0)
3.所有火柴棍必须全部用上。
输入格式:
一个整数n,表示火柴棍的总数。
输出格式:
符合条件的等式,每行一组。(顺序由第一个数从小到大)
样例输入:
18
样例输出:
0+4=4
0+11=11
1+10=11
2+2=4
2+7=9
4+0=4
7+2=9
10+1=11
11+0=11
分析:
呵呵,我相信很多人看完题目后都是灵光乍现,脑袋里闪出两个字:枚举!
是的,这玩意儿最好做的就是枚举,但这并不意味着没有其他方法。
既然是要找到形如A+B=C这样的等式,那最简单的方法就是分别枚举A,B,C。
好现在问题来了:怎么找范围?
呵呵,我们只需要在0~1111之间枚举就可以了。你问我为什么?因为我给的题目中火柴棍最多只有24根,除去+号和=号最多只有20根,而0~9的数字之中,1用到的火柴棍最少,只需要2根,而20个火柴棍刚好能组成10个1,那也就是说,ABC三个数所需的根数都<=1111。
这里只需要枚举A,B就可以了,C可以通过A,B算出来,这样减少了时间复杂度,有的时候做题也是这样啊,要去实行剪枝、优化程序。我的思路是将0~9所需的火柴数分别用一个a[]数组存起来。
OK,直接给代码,我与标注释,应该看得懂吧(汗):
#include<bits/stdc++.h>
using namespace std;
int f(int x)
{
int num=0;//用来记录初始化,一定要记得初始化。
int a[10]={6,2,5,5,4,5,6,3,7,6};
//用一个a[]数组存0~9分别需要的火柴棍数量。
while(x/10!=0)//如果这个数除以10不等于0的话,那就证明它至少有两位。
{
//获得x的末尾数字并将此数所需要用到的火柴棍棍数累加到num中。
num+=a[x%10];
x/=10;//去掉x末尾的数字,这里的操作就是在遍历一个数的各位。
}
num+=a[x];
return num;
}
int main()
{
int a,b,c,n,sum=0;
cin>>n;
for(int a=0;a<=1111;a++)
{
for(int b=0;b<=1111;b++)
{
c=a+b;
if(f(a)+f(b)+f(c)==n-4)//n-4就是减去+号和=号所用的火柴棍。
{
cout<<a<<'+'<<b<<'='<<c<<endl;
}
}
}
return 0;
}
哈哈,自豪一下,减少时间复杂度是我自己想出来的呢。
不要小看!原本是O(N^3)优化到了O(N^2)呢!
还是那句话,写程序要多动脑子,多想,不然会没有突破。