100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
从标准输入读入一个正整数N (N<1000*1000)
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
题目要求,输入一个数,将其转换为一个整数+分数(a+b/c)的形式,且不重复地包含1~9所有数字。
解题思路:
根据题意可知a,b,c包含了1~9所有数字且不重复,也就是说abc是数字1~9的一种排列。
所以,我们可以先对数字数list进行全排列,然后再划分a,b,c。如果这种划分满足条件:a+b/c=number,b%c=0,就记录数+1。
这种解法的关键点在于:
1.求出数字数list的全排列;
2.划分数字a,b,c 各自的位数。
求全排列的方法这里采用递归分治法。递归函数,函数循环查找数组,将数字数组所有数字查找出来,每查找出一个数,就调用自己,查找出除了这个数之外数组的全排列……
数字a,b,c位数的划分:a的位数i在1和number的长度nlength之间,那么,b的第一位为s[nlength],c的最后一位为s[8],bc的长度为9-i;因为b/c为整数,所以b的长度至少为bc长度的一半,不然b/c不可能为整数。
假设数字数list的一种全排列为s[9],a的长度为i,a的值为na,则b的最后一位可以用c的最后一位来求,即(na*s[8])%10,借b的最后一位和c的最后一位可以判断b和c的位数划分。
实现代码如下:
import java.util.Scanner;
public class Main{
static int nlength=0;//输入整数n的长度
static int n=0;
static int count =0;//记录带分数个数
static int[] s=new int[] {1,2,3,4,5,6,7,8,9};//定义数组
public static void main(String[] args)
{
Scanner input=new Scanner(System.in);
n=input.nextInt();
// long start=System.currentTimeMillis();
nlength=(n+"").length();//记录n的长度
allrang(0);//数组s的全排列
System.out.println(count);
// long end=System.currentTimeMillis();
// System.out.println(end-start);
}
public static void allrang(int k)
{
if(k==s.length-1)//遍历了一遍数组s
{
process();
return;
}
else
{
for(int i=k;i<s.length;i++)//全排列数组s
{
{int temp=s[k];s[k]=s[i];s[i]=temp;}//交换前缀,使之产生下一个前缀
allrang(k+1);//继续全排列
{int temp=s[k];s[k]=s[i];s[i]=temp;}//将前缀交换回来,继续做上一个前缀的排列
}
}
}
public static void process()
{
String str="";
for(int i=0;i<s.length;i++)str+=s[i];//将数组s转换为字符串数组str
int a,b,c,na,bc,bl;//n=a+b/c
for(int i=1;i<=nlength;i++)
{
a=dev(0, i-1);//取得a的数值
na=n-a;//取得b/c的数值
if(na<=0)return;
bc=9-i;//取得b和c的位数
bl=(na*s[8])%10;//用c的最后一位,即数组的最后一位s[8]来取得b的最后一位
for(int j=i+bc/2-1;j<=7;j++)//b至少占有bc长度的一半,不然b/c不可能为整数
{
if(s[j]==bl)//找到符合的位置,即b的最后一位
{
b=dev(i, j);
c=dev(j+1, 8);
if(b%c==0&&b/c==na)
{
count++;
}
break;
}
}
}
}
public static int dev(int a,int b)
{
int ans=0;
for(int i=a;i<=b;i++)
{
ans+=s[i];
ans*=10;
}
return ans/10;
}
}