历届试题 带分数 (全排列)——全排列函数

该博客讨论了如何计算一个正整数使用1到9的数字不重复组成带分数的所有表示方法。通过数论知识确定分母和分子的位数范围,并利用全排列函数next_permutation进行求解,举例说明了100的不同带分数表示形式的统计方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

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


基本思路



这个题只需写出“123456789”的全排列,然后从上面截取运算即可


先普及一个数论知识,a/b=c 若c为x位,b为y位,c为z位,x的最大值为y+z,最小值为x(max)-1


如果设整数位数为bit1,分数部分位数为bit2,分母为x位,分子为y位

,全排列有9位则根据数论知识一定有

x-y=bit2  x+y=9-bit1

算出来x=(9-bit1+bit2)/2 即分母最多有x=(9-bit1+bit2)/2位 最少有(9-bit1+bit2)/2-1位


设n的百分数表示形式为basic+fz/fm


比如当n=100

当basic=1时 分子最多有5位最少有4位

排列数a到了“123456789” ,只需截取两个就可以

a截取为1 2345 6789 发现1+2345/6789!=100舍去

再截取1 23456 789 发现1+23456/789!=100 舍去

当basic=12时 分子最多有4位 最少有3位
排列数a到了“123456789” ,只需截取两个就可以
a截取为12 3456 789 发现12+3456/789!=100舍去
再截取12 345 6789 发现12+345/6789!=100 舍去

当basic=123时

123>100 不再循环



再比如当n=100

排列数a到了823546197

当basic=8时,只需两个

截取a截取为8 2354 6197 发现8+2354/6197!=100舍去

再截取8 23546 197 发现8+23546/197!=100 舍去


当basic=82时只需截取两个

截取a截取为82 3546 197 发现82+3546/197=100计数器Count+1
再截取82 354 6197 发现82+354/6197!=100 舍去

当basic=823时

823>100 不再循环


至于全排列我没用DFS

我用了stl中的一个输出全排列函数next_permutation(,),这个函数只能对一个字符串a,取a的下一个全排列字符串

具体用法如下:(输出一个字符串所有全排列)

#include<iostream>  
#include<algorithm>  
#include<cstring> 
#include<string> 

using namespace std;
int main()  
{  
	//方法一用char数组 
    char a[10];
	gets(a);
	sort(a,a+strlen(a));//因为要输出所有的所以对输入的要进行排序
	cout<<a<<endl;
	while(next_permutation(a,a+strlen(a)))
		cout<<a<<endl;
	//方法二用string
	cout<<endl;
	string s;
	cin>>s;
	sort(s.begin(),s.end());
	cout<<a<<endl;
	while(next_permutation(s.begin(),s.end()))
		cout<<s<<endl;
    return 0;  
} 

本题我还用到了一个atoi函数


atoi用法如下:


atoi (表示 alphanumeric to integer)是把字符串转换成整型数的一个函数,


原型:int atoi(const char *nptr);



#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int Count=0;
char a[10]={'1','2','3','4','5','6','7','8','9',0};
int bits(int num)//求一个数的位数
{
	int bit=0;
	while(num)
	{
		bit++;
		num/=10;
	}
	return bit;
}
char *Sub(int s,int e)//截取字符串,从下标s截取到e
{
	if(s>e)
		return 0;
	char *ans=new char;
	int k=0;
	for(int i=s;i<=e;i++)
		ans[k++]=a[i];
	ans[k]=0;
	return ans;
}
void isval(int num,char seq[],int basic)//判断某一全排列是否有符合要求的截取方案
{
	int bit1,bit2,fm,fz;//含义见上面解释
	double ans;
	char *s1=new char,*s2=new char;
	bit1=bits(basic);
	bit2=bits(num-basic);
	for(int i=(9-bit1+bit2)/2-1;i<=(9-bit1+bit2)/2;i++)//解释见上面,只截取两次
	{
		fz=atoi(Sub(bit1,bit1+i));
		fm=atoi(Sub(bit1+i+1,8));
		ans=(fz*1.0)/fm;
		if(ans==(double)(num-basic))
			Count++;		
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<bits(n);i++)
		if(atoi(Sub(0,i))<n)
			isval(n,a,atoi(Sub(0,i)));
	while(next_permutation(a,a+9))//全排列
       for(int i=0;i<bits(n);i++)
    		if(atoi(Sub(0,i))<n)
			isval(n,a,atoi(Sub(0,i))); 
	cout<<Count<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值