定义十进制中没有重复数字的正整数为P数,指定p数按升序排列所得序列为指定P序列;
试求指定m位P数的个数,并求出m位P序列的第n项;
输入正整数m(2<=m<=10)和n(2<=n),输出m位P数的个数,同时输出m位P序列的第n项(若n大于m位P数的个数,则输出提示信息);
1.枚举设计:
(1)、枚举设计要点;
通过循环求得m位最小与最小的P数a、b,设置递增循环枚举a~b中的所有整数x,以确保序列为升序排序;
分离x的m个数字,并用数组f[k]统计数字k(0~9)的个数,判别:若f[k]>1(0~9),存在重复数字,返回;否则,f[k]<=1(0~9),不存在重复数字,x即为P数,用s统计其个数,并用变量z记录其中的第n个;
最后输出序列个数s和序列第n项z;
(2)、程序设计;
#include
int main()
{
int k,m,t,f[10];
long a,b,n,s,w,x,z;
printf("请输入m,n:");
scanf("%d,%ld",&m,&n);
a=10;
b=98;
for(k=3;k<=m;k++)
{
a=a*10+k-1; /*a、b为m位最小与最大的P数*/
b=b*10+10-k;
}
s=0;
for(x=a;x<=b;x++) /*枚举[a,b]中的每一个整数*/
{
w=x;
for(k=0;k<=9;k++)
f[k]=0;
while(w>0) /*分解x的各数字并分别累计*/
{
k=w%10;
f[k]++;
w=w/10;
}
for(t=0,k=0;k<=9;k++)
if(f[k]>1) /*测试是否有重复数字*/
{
t=1;
break;
}
if(t==0)
{
s++; /*统计P数的个数*/
if(n==s) /*记录第n项*/
z=x;
}
}
if(s
(3)、程序运行示例及其注意事项:
请输入m,n:5,2017
5位P序列共27216项
序列第2017项为17023
以上枚举设计简单可行,但当m、n比较大时运行时间太长,有进一步改进与优化的必要;
2.程序的改进与优化:
(1)、优化设计要点;
1)、计算m位P数的个数;
显然m位P数的最高位可于1,2,……,9中取一个数字;
除最高位外其余的m-1为可于0~9中与最高位不同的其余9个数字中选m-1个,即为排列数A(9,m-1),存储在数组元素a[m-1]中;
除高二位外其余的m-2位可于0~9中与高二位不同的其余8个数字中选m-2个,即为排列数A(8,m-2),存储在数组元素a[m-2]中;
· · · · · ·
个位数字可于0~9中与高m-1位不同的11-m个数字中选1个,即为排列数A(11-m,1),存储在数组元素a[1]中;
显然m位P数的个数为9*a[m-1];
2)、由a数组元素确定P序列的第n项的各个数字;
根据n中含c=n/a[m-1]个a[m-1]确定最高位数字,n=n%a[m-1]为确定下一位数字做准备;然后根据n中含c=n/a[m-2]个a[m-2]确定次高位的数字,n=n%a[m-2]为确定下一位数字做准备;
一般地,根据n中含c=n/a[j]确定从高位开始的第j位数字:
c=n/a[j];n=n%a[j];(j=m-1,m-2,……,0);
c=(int)floor(n/a[j]);n=fmod(n,a[j]);
为方便计算,引入a[0]=1;,选择尚未选取的第c个为最低位数字;
3)、设置b数组,为避免重复选取数字提供顺利;
首先b[i]=1;(i=0,1,……,9);
若已选取i作为某一位,则b[i]=0;,这样以后加b[j]和不增长,即在下一位数字选取时不可能选取i,避免了重复数字,这是P数的要求;
4)、特殊处理;
因最高位数字不能从0开始,故设置变量d:开始时d=1,以后均为d=0;
(2)、程序设计:
#include
#include
int main()
{
int c,d,i,j,k,m,s,b[10];
double n,t,a[10];
printf("请输入m,n:");
scanf("%d,%lf",&m,&n);
for(k=0;k<=9;k++)
b[k]=1;
for(t=1,j=1;j<=m-1;j++)
{
t=t*(10+j-m);
a[j]=t;
}
printf("%d位P序列共%.0f项 \n",m,9*a[m-1]);
if(n>9*a[m-1])
{
printf("n超过总项数!\n");
return;
}
else
printf("序列第%.0f项为 ",n);
a[0]=1;
d=1;
for(j=m-1;j>=0;j--)
{
c=(int)floor(n/a[j])+d;
n=fmod(n,a[j]);
if(n==0 && j>0)
{
c--;
n=a[j];
}
s=0;
i=-1;
if(j>0)
{
while(s<=c)
{
i++;
s+=b[i];
}
printf("%d",i);
b[i]=0;
d=0;
}
else
{
while(s
(3)、程序运行示例及其注意事项:
请输入m,n:10,1234567
10位P序列共3265920项
序列第1234567项为 4369702158
当m比较大时,应用枚举很难完成序列的统计与确定,而应用优化设计来求解则要简明快捷得多;
枚举设计可在较小范围内验证优化设计是否准确;