Subset sequence

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 11478 Accepted Submission(s): 4888
Problem Description
Consider the aggregate An= { 1, 2, …, n }. For example, A1={1}, A3={1,2,3}. A subset sequence is defined as a array of a non-empty subset. Sort all the subset sequece of An in lexicography order. Your task is to find the m-th one.

Input
The input contains several test cases. Each test case consists of two numbers n and m ( 0< n<= 20, 0< m<= the total number of the subset sequence of An ).
Output
For each test case, you should output the m-th subset sequence of An in one line.

Sample Input
1 1
2 1
2 2
2 3
2 4
3 10
Sample Output
1
1
1 2
2
2 1
2 3 1
对所有的子序列按字典顺序排列
子集里元素考虑顺序了,
题意:
1.一个规则的数组,从1...n的
2.对这个数组进行有规则的排序
例如 n=3时
⑴ 1
⑵ 1 2
⑶ 1 2 3
⑷ 1 3
⑸ 1 3 2
⑹ 2
⑺ 2 1
⑻ 2 1 3
⑼ 2 3
⑽ 2 3 1
⑾ 3
⑿ 3 1
⒀ 3 1 2
⒁ 3 2
⒂ 3 2 1
3.问你,给你一个m,让你输出该数组第几个的表达形式

既然分组了,要确定m在第几组里,所以要求每一组的子集个数
分组后每组子集个数为c[n]
总子集数为 f[n]
所以c[n]=f[n]/n
f[n]=n*(f[n-1]+1)
∴c[n] = n[f[n-1] + 1] / n = f[n-1] + 1
∵f[n-1] = (n-1) * c[n-1]
∴c[n] = (n-1) * c[n-1] + 1

程序步骤实例解说:

n=3,m=10时,有
{1}
{1, 2}
{1, 2, 3}
{1, 3}
{1, 3, 2}
{2}
{2, 1}
{2, 1, 3}
{2, 3}
{2, 3, 1}
{3}
{3, 1}
{3, 1, 2}
{3, 2}

  1. 求得t=2,先输出第2组首元素2
  2. 再去掉前面不需要的分组,和首元素,剩下唯一一组子集:因此此时m-=((t-1)*c[n]+1)=4
    //{}
    {1}
    {1, 3}
  3. 然后再分成两组, t=m/c[n]+(m%c[n]>0?1:0)求得当前在第t=2组
    输出第2组首元素3,再去掉前面不需要的分组,和首元素,剩下唯一一组子集
    因此此时m-=((t-1)*c[n]+1)=1
    //{}
  4. 然后剩最后一组, t=m/c[n]+(m%c[n]>0?1:0)求得当前在第t=1组
    输出第1组首元素1,和首元素,剩下唯一一组子集
    {}//空集
    因此此时m-=((t-1)*c[n]+1)=0

    将该子集的下一个元素到最后一个的值+1,注意这个规律:在第i组,首元素为i,删除首元素后,在第i个子集后首元素均变大+1.
#include<iostream>
using namespace std;
int main()
{
	int i;
	int n;     //一共多少元素
	int t;     //所求集合位于分组后的第几组
	__int64 m;   //位于第几个元素
	__int64	c[21]={0};  //分组后每组个数
	int s[21];  //将子集按字典序分组后每组的初始首元素 
	
	for(i=1;i<21;i++)
	{
		c[i]=c[i-1]*(i-1)+1;
	} 
	while(cin>>n>>m)
	{
		for(i=0;i<21;i++)
		{
			s[i]=i;
		}
		while(n>0&&m>0)
		{
			t=m/c[n]+(m%c[n]>0?1:0);
			if(t>0)
			{
				cout<<s[t];
				for(i=t;i<=n;i++)
				{
					s[i]=s[i+1];
				}
				m-=((t-1)*c[n]+1);//减去(t-1组总子集数+1),m变为表示在剩余子集中位于第几个
				putchar(m==0?'\n':' '); 
			}
			n--;
		}
	}
	return 0;
} 
 posted on 2020-04-01 20:13  My_serendipity  阅读(89)  评论(0编辑  收藏  举报