资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
输入格式
从标准输入读入一个正整数N (N<1000*1000)
输出格式
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
样例输入1
100
样例输出1
11
样例输入2
105
样例输出2
6
思路:
number=a+b/c
将数组全排列后迭代确定a的值,根据((number - a) * list[8]) % 10
计算b的最后一位数,再确定其正确性
详细解析请参考:蓝桥杯:带分数(全排列)(包含有暴力枚举的超时方法)
提交代码
#include <stdio.h>
/*思路:将list[1,2,3,4,5,6,7,8,9]数组进行全排列,然后对于每一种排列进行处理
处理方法:将list数组划分为三部分a,b,c,判断是否满足number == a+b/c && b%c == 0;
具体见分析.........
*/
int x = 0, number = 0, count = 0;
//交换a,b两数
void Swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
//将数组区间转化为数字
int getNum(int list[], int f, int r)
{
int i = 0, num = 0;
for (i = f; i <= r; i++)
num = list[i] + num * 10; //进位
return num;
}
//进行全排列并对每种排列结果进行处理
void Prim(int list[], int k, int m)
{
if (k == m - 1) //前缀是最后一个位置,此时出现一种排列数.
{
int a = 0, b = 0, c = 0, bLast = 0; //带分数:a+b/c
for (int i = 0; i < x; i++) //i表示a的末尾位置,不会超过number位数
{
a = getNum(list, 0, i); //将list数组中的[0-i]转化为数字,赋值给a
bLast = ((number - a) * list[8]) % 10; //确定b最后一个数字
for (int j = i + (8 - i) / 2; j < 8; j++)//从list数组中间位置开始找b末尾位置
{
if (list[j] == bLast) //找到b尾部
{
b = getNum(list, i + 1, j); //将list数组中的[i+1-j]转化为数字,赋值给b
c = getNum(list, j + 1, 8); //将list数组中的[j+1-8]转化为数字,赋值给c
if (b % c == 0 && a + b / c == number) //判断合理性
{
//printf("%d+%d/%d\n",a,b,c); //打印每种情况
++count;
}
break;
}
}
}
}
else
{
for (int i = k; i < m; i++) //全排列数组list[]
{
//交换前缀,使之产生下一个前缀.
Swap(list[k], list[i]); //>>A
Prim(list, k + 1, m); //>>B
//将前缀换回来,继续做上一个的前缀排列.//>>C
Swap(list[k], list[i]);
}
}
}
//主函数
int main()
{
int temp = 0;
int list[] = { 1,2,3,4,5,6,7,8,9 }; //定义全排列数组
scanf("%d", &number);
temp = number;
while (temp != 0) //统计number总共多少位
{
++x;
temp /= 10;
}
Prim(list, 0, 9);
printf("%d", count); //打印总共多少种
return 0;
}
参考链接:https://blog.csdn.net/jopus/article/details/18998403