zoukankan      html  css  js  c++  java
  • HDU Subset sequence

    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}
    {3, 2, 1}

    1. 求得t=2,先输出第2组首元素2
    2. 再去掉前面不需要的分组,和首元素,剩下唯一一组子集:因此此时m-=((t-1)*c[n]+1)=4
      //{}
      {1}
      {1, 3}
      {3}
      {3, 1}
    3. 然后再分成两组, t=m/c[n]+(m%c[n]>0?1:0)求得当前在第t=2组
      输出第2组首元素3,再去掉前面不需要的分组,和首元素,剩下唯一一组子集
      因此此时m-=((t-1)*c[n]+1)=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--;
    		}
    	}
    	return 0;
    } 
    
  • 相关阅读:
    吾爱破解 培训第十课:探寻逆向新航标x64平台脱壳与破解实战 笔记
    吾爱破解 培训第八、九课:短兵相接深入浅出探讨脱壳细节 笔记
    十大经典排序算法(转自 www.runoob.com)
    吾爱破解 培训第一课:破解基础知识之介绍常见工具和壳的特征 笔记
    吾爱破解 培训第三课:改头换面之修改版权和资源 笔记
    吾爱破解 软件虚拟机保护分析资料整理 笔记
    吾爱破解 新手脱壳破解常见问题 笔记
    吾爱破解 培训第七课:手把手教你从实例看如何攻破常见的网络验证 笔记
    吾爱破解 培训第五课:反击作者的挑衅实战解除程序重启验证 笔记
    GDB基础
  • 原文地址:https://www.cnblogs.com/serendipity-my/p/12615202.html
Copyright © 2011-2022 走看看