杭电ojSubset sequence(子集序列)

这篇博客探讨了如何利用动态规划找到给定集合的子集序列,并按字典序排序。通过示例解释了算法思路,展示了如何计算每个子集序列的数量,并给出了一段C++代码实现。该算法对于输入的集合大小n和目标序列位置m,能有效地找出第m个子集序列。
摘要由CSDN通过智能技术生成

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

思路

用dp来找到规律
a[i] = a[i - 1] * (i - 1) + 1
1 2 5 16 。。。
以3 10举例
现在序列{1,2,3}
现在是3个5种小情况组成的15种情况
1
12
123
13
132(5)

2
21
213
23
231(5)

3
31
312
32
321(5)
首先10是第二组中的数
m -= (d - 1) * a[n] + 1;//d:第d组数(上一行我们知道是第二组)
10-(15+1)=4
输出a[2]=2并从序列中拿出
序列中:{1,3}
现在是两个2种小情况组成的4种情况
1
13(2)
3
31(2)
4是第二组中的数
4-(1
2+1)=1
输出a[1]=1并从序列中拿出
序列中:{3}
1是第一组中的数
1-(0*1+1)=0
输出a[1]=3并从序列中拿出
序列为空,程序结束
输出结果为2 1 3

程序代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<iomanip>
typedef long long l;
using namespace std;
int main()
{
	l a[25] = { 0 };
	a[1] = 1;
	a[2] = 2;
	for (int i = 3; i < 21; i++)
	{
		a[i] = a[i - 1] * (i - 1) + 1;//每个n子列序列的数量/n
	}
	l n, m;
	while (cin >> n >> m)
	{
		bool first = true;
		l b[25] = { 0 };//子集序列,可以在里面删除数据
		for (int i = 1; i <= n; i++)
		{
			b[i] = i;
		}
		if (m == 1)
		{
			cout << "1" << endl;
			continue;
		}
		while (n && m)
		{
			l c = m % a[n];//是否求余为0
			l d = m / a[n];//子列序列中的第几个
			if (c)d++;//如果求余不为0,则d要加一
			if (!first)cout << " ";
			cout << b[d];
			for (int i = d; i < n; i++)
			{
				b[i] = b[i + 1];//将输出上的数据删除(让后面的数据覆盖前面的数)
			}
			m -= (d - 1) * a[n] + 1;//是子列序列中第d个子列序列中的第几个
			n--;
			first = false;
		}
		cout << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值