【蓝桥杯】 PREV-3 带分数(搜索,全排列)

资源限制
时间限制: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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值