排序集合

对于集合N={1,2,…,n}的子集,定义一个称之为“小于”的关系:
设S1={X1,X2,…,Xi},(X1<X2<…<Xi),S2={Y1, Y2, …,Yj},(Y1<Y2<…<Yj),如果存在一个k,(0≤k≤min(i,j)),使得X1=Y1,…,Xk=Yk,且k=i或X(k+1)<Y(k+1),则称S1“小于”S2。
你的任务是,对于任意的n(n≤31)及k(k<2n),求出第k小的子集。
输入输出格式
输入格式:
输入文件仅一行,包含两个用空格隔开的自然数,n和k。
输出格式:
输出文件仅一行,使该子集的元素,由小到大排列。空集输出0。
输入输出样例
输入样例#13 4
输出样例#11 2 3
题目描述

首先观察,可以得到如下:

当n=3时:

{}<
{1}<{1,2}<{1,2,3}<{1,3}<
{2}<{2,3}<
{3}
当n=4时:

{}<
{1}<{1,2}<{1,2,3}<{1,2,3,4}<{1,3}<{1,3,4}<{1,4}<
{2}<{2,3}<{2,3,4}<{2,4}<
{3}<{3,4}<
{4}
当n=5时:

{}<
{1}<{1,2}<{1,2,3}<{1,2,3,4}<{1,2,3,4,5}<{1,3}<{1,3,4}<{1,3,4,5}<{1,4}<{1,4,5}<{1,5}<
{2}<{2,3}<{2,3,4}<{2,3,4,5}<{2,4}<{2,4,5}<{2,5}<
{3}<{3,4}<{3,4,5}<{3,5}<
{4}<{4,5}<
{5}

这样列出就可发现规律了。

具体算法为:先推出第k小的一个自己的第一个数字是多少,从而确定第一个数字,

再推出第二个数字,从第一个数字加1一直计算累加集合个数,

直到的到不超过k的最大的那个数字,就是第二个数字,

这样一直递推,推倒最后一个。

注意:终止条件已推出n个数字或第i个数字为空。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<string>
 7 #include<queue>
 8 using namespace std;
 9 int n,k,x[100];
10 int main()
11 {
12     scanf("%d%d",&n,&k);
13     k--;
14     if(k==0) {printf("0");return 0;}
15     x[0]=1;
16     for(int i=1;i<=33;++i) x[i]=x[i-1]*2;
17     for(int i=1;k && i<=n;++i)
18     {
19         if(k>x[n-i]) k-=x[n-i];
20         else{
21             k--;
22             printf("%d ",i);
23         }
24     }
25     return 0;
26 }
27  
View Code

 参考来源:https://www.luogu.org/problemnew/solution/P1243

原文地址:https://www.cnblogs.com/adelalove/p/9196011.html