排序集合

题目描述

对于集合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 = 3 时。
第1小的是空集对吧。第2小的是\({1}\)对吧。而以1开头的集合最大在第几名呢。\(1+2^{n-1}\)名。即第5名。
如果大于\(1+2^{n-1}\)呢,那直接跳过1,开始从下一个数字头开始。
这样。继续考虑以2开头的。最多有多大呢以2开头的集合有\(2^{n-2}\)对吧。这样直接加上前面的就可以得到最大排名。

这样就可以实现程序了。

但实际上却不好做。
为什么?
不好确定具体元素。

换个方式。每跳过一个元素就直接减去以这个元素开头的集合数目。
然后做下去。

代码如下。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int maxn = 2000;

int n,k;
int bit[50];
int main()
{
  scanf("%d%d",&n,&k);
  bit[0] = 1;
  for(int i = 1;i <= n;i++)
    bit[i] = bit[i-1]*2;
  if(k <= 1) cout<<0<<endl;
  else{
    k--;
    for(int i = 1;i <= n;i++)
    { 
      if(k <= 0) break;
      if(k <= bit[n-i]){
        k--;
        printf("%d ",i);
      }else 
        k -= bit[n-i];
    }
  }
}
posted @ 2017-09-10 21:32  rsqppp  阅读(155)  评论(0)    收藏  举报