9、题目标题:带分数(满分16分)
100 可以表示为带分数的形式:100 = 3 + 69258 / 714
还可以表示为:100 = 82 + 3546 / 197
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
题目要求:
从标准输入读入一个正整数N(N<1000*1000)
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
例如:
用户输入:
100
程序输出:
11
再例如:
用户输入:
105
程序输出:
6
资源约定:
峰值内存消耗 <64M
CPU消耗 < 3000ms
分析:这道题的思路还是很清晰的,首先要明白题意,=号右边的数字不能任何重复,而且不能含有0,
给定一个数值n,n = left + up/down
也就是需要遍历left,再遍历down,最后得出(n-left) * down的乘积是否满足上述条件即可,所以只需要两个循环。
难点就是有很多需要处理的地方,比如说标记数字,对标记的数字进行取消标记等等,下面看代码。
#include <iostream>
#include <map>
#include <cstring>
#include <cstdlib>
using namespace std;
int flag[10] ; //标记数字
int sum;
int check(int x)
{
int mod; //玉余数
int f = 0;
int k = 0;
int ary[10]={0}; //将余数存进一个数组中
int aryy[10]={0}; //判断一个数中是否有重复的数字
while(x)
{
mod = x%10;
ary[k++] = mod;
if(flag[mod] || (++aryy[mod]) == 2 || !mod) //最后一个是判断有无0
{
f = 1; //只要有重复的就跳出结束
return 0;
}
x /=10;
}
if(f == 0) //如果执行到这一步,f只能=0 所以这个判断条件可以去掉
{
for(int i=k-1;i>=0;i--)//这时候再对数字进行标记
{
flag[ary[i]] = 1;
}
return k; //返回这个数字的位数
}
}
void change(int x) //这个函数是用来对上一次循环所标记的数字取消标记
{
int mod;
while(x)
{
mod = x%10;
flag[mod] = 0;
x /= 10;
}
}
void main()
{
int i,j,k;
int n,m;
int up,down;
int left;
int last = 0;
int cnt = 0;
cin>>n;
memset(flag,0,sizeof(flag));
for(left=1;left<n;left++)
{
int l = check(left);
if(l)
{
for(down = 1;down<100000;down++)
{
int d = check(down);
if(d)
{
up = (n-left)*down;
int u = check(up);
if(u)
{
if(l+d+u == 9) //还要判断是否满足9个数字都被使用了
{
//cout<<left<<" "<<down<<" "<<up<<endl;
cnt++;
}
change(up);
}
change(down);
}
}
change(left);
}
}
cout<<cnt<<endl;
}