火柴棒等式
[NOIP2008 提高组] 火柴棒等式
题目描述
给你 \(n\) 根火柴棍,你可以拼出多少个形如 \(A+B=C\) 的等式?等式中的 \(A\)、\(B\)、\(C\) 是用火柴棍拼出的整数(若该数非零,则最高位不能是 \(0\))。用火柴棍拼数字 \(0\sim9\) 的拼法如图所示:

题目分析
- 首先,我们看到这个题目第一个想到的是什么?反正我想到的是打表,为什么捏??看一下 \(n\) 的范围 —— 24
思路也非常简单,其中从 \(1\) 到 \(12\) 都是 \(0\) 种可能。可以省去一大半可能性,而且,如果是打表的话,完全不用考虑时间复杂度,是不是很 \(nice\) 。
我们来思考另一个问题:如何生成打表器?
手算当然是可以的,但是错误率比较高,而且效率较低。所以,我们把这个艰巨的任务交给我们的计算机来实现把!!
\(code\)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int val[10] = { 6,2,5,5,4,5,6,3,7,6 };
int need(int num) {
// 数字num需要的火柴数
int sum = 0;
while (num / 10) { // 防止num = 0
sum += val[num % 10];
num /= 10;
}
sum += val[num];
return sum;
}
int ans[25]; // n < 25 时的答案
int main() {
int a, b;
for (int a = 0; a <= 1111; a++) {
for (int b = 0; b <= 1111; b++) {
int sum = need(a) + need(b) + need(a + b) + 4;
if (sum <= 24) ans[sum]++;
}
}
for (int i = 0; i < 25; i++) {
printf("%d,", ans[i]);
}
return 0;
}
经亲自试验,此代码不可以AC,但可以生成打表。
输出
0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,8,9,6,9,29,39,38,65,88,128,
好的,那么我们就可以把代码写出来了
\(code\)
#include <bits/stdc++.h>
using namespace std;
int x[25]={0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,8,9,9,29,39,39,38,65,88,128};
int main(){
int n;
cin>>n;
cout<<x[n];
return 0;
}
- 然后,我们再来想一想,除了打表,还有没有别的方法呢?
答案当然是肯定的。
我们可以模拟出每一个算式,然后去判断可不可以,也就是成不成立。
比如,我们开一个 \(for\) 循环,把每一种可能性都列举一遍,就是判断成不成立,然后去判断小棒够不够。
这里运用了一个基本的知识点:拆数
\(code\)
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int num(int x)
{
int ans=0,k[10]={6,2,5,5,4,5,6,3,7,6};//定义一个计数变量,一个记录每个数字火柴棒数量的数组
if(x==0) return 6;//确定边界
while(x!=0)//开始拆数
{
ans=ans+k[x%10];//把拆出来的数每个数位的火柴棒数量累加就是这个数的火柴棒数量
x=x/10;//拆下一位
}
return ans;//返回答案
}
int main()
{
int n,cnt=0;//计数变量,注意不要和前面的ans混了
cin>>n;
for(int i=0;i<=1111;i++)//开始第一层循环
{
for(int j=0;j<1111;j++)//第二层
{
if(num(i)+num(j)+num(i+j)==n-4)//判断是否
cnt++;//计数变量++
}
}
cout<<cnt;
return 0;
}
就是把数字的每一位拆分出来作为一个单独的个体,然后去模拟一遍就可以了。
注释非常的清楚欸
码字不易,不要\(copy\)
拜拜喽

浙公网安备 33010602011771号