算法提高 排列数
时间限制:1.0s 内存限制:256.0MB
问题描述
0、1、2三个数字的全排列有六种,按照字母序排列如下:
012、021、102、120、201、210
输入一个数n
求0~9十个数的全排列中的第n个(第1个为0123456789)。
012、021、102、120、201、210
输入一个数n
求0~9十个数的全排列中的第n个(第1个为0123456789)。
输入格式
一行,包含一个整数n
输出格式
一行,包含一组10个数字的全排列
样例输入
1
样例输出
0123456789
数据规模和约定
0 < n <= 10!
觉得蓝桥杯练习系统比较坑爹的地方就在于这道题用提示所说的枚举、循环根本行不通,一开始写好了这样暴力的代码,结果根本无法运行。暴力代码如下:
#include<stdio.h>
int main()
{
int a1,a2,a3,a4,a5,a6,a7,a8,a9,a0,sum=0,flag=0;
long long n;
scanf("%d",&n);
for(a0=0; a0<=9; a0++)
{
for(a1=0; a1<=9; a1++)
{
if(a0==a1)
continue;
for(a2=0; a2<=9; a2++)
{
if(a2==a0||a2==a1)
continue;
for(a3=0; a3<=9; a3++)
{
if(a3==a0||a3==a1||a3==a2)
continue;
for(a4=0; a4<=9; a4++)
{
if(a4==a0||a4==a1||a4==a2||a4==a3)
continue;
for(a5=0; a5<=9; a5++)
{
if(a5==a0||a5==a1||a5==a2||a5==a3||a5==a4)
continue;
for(a6=0; a6<=9; a6++)
{
if(a6==a0||a6==a1||a6==a2||a6==a3||a6==a4||a6==a5)
continue;
for(a7=0; a7<=9; a7++)
{
if(a7==a0||a7==a1||a7==a2||a7==a3||a7==a4||a7==a5||a7==a6)
continue;
for(a8=0; a8<=9; a8++)
{
if(a8==a0||a8==a1||a8==a2||a8==a3||a8==a4||a8==a5||a8==a6||a8==a7)
continue;
for(a9=0; a9<=9; a9++)
{
if(a9==a0||a9==a1||a9==a2||a9==a3||a9==a4||a9==a5||a9==a6||a9==a7||a9==a8)
continue;
sum++;
if(sum==n)
{
printf("%d%d%d%d%d%d%d%d%d%d\n",a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);
flag=1;
break;
}
}
if(flag)
break;
}
if(flag)
break;
}
if(flag)
break;
}
if(flag)
break;
}
if(flag)
break;
}
if(flag)
break;
}
if(flag)
break;
}
if(flag)
break;
}
if(flag)
break;
}
return 0;
}
这个题的正确解法应该是DFS搜索,简单明了。代码如下
#include<stdio.h>
#include<string.h>
long long n,sum;
int vis[10];//用来标记数字i是否被用了,即是否已被放在了排列中
int a[10];
void dfs(int pos)
{
if(pos==10)//表示当前数组a中已有10个数字
{
sum++;
if(sum==n)
{
for(int i=0; i<10; i++)
printf("%d",a[i]);
printf("\n");
}
}
for(int i=0; i<=9; i++)//枚举数字0到数字9
{
if(!vis[i])//若数字i还没被放在当前排列中
{
a[pos]=i;//将i赋给当前排列a数组的第pos位置
vis[i]=1;//数字i已放入排列中,标记为1
dfs(pos+1);//继续搜索下一个位置
vis[i]=0;//清除标记
}
}
}
int main()
{
while(~scanf("%lld",&n))
{
memset(vis,0,sizeof(vis));
sum=0;
dfs(0);
}
return 0;
}