排序集合
题目描述
对于集合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];
}
}
}

浙公网安备 33010602011771号