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

    我是把它当做一道数学题来做的。

    这篇题解写的有点啰嗦,但是是我最原始的思维过程。

    对于一个集合An= { 1, 2, …, n },在n比较小的情况下,在纸上按字典顺序把所有子集排列一下。

    以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
    n=3的情况

    容易看出前5个打头的是1,紧接着5个子集打头的是2,最后5个开头的是3。

    拿前五个来说,除了第一个,后面四个不看开头的1,后面的排列形式和n=2的子集的排列很相似。

    f(n)代表集合An所有子集的个数,那么有递推关系:

    f(n) = n * (f(n - 1) + 1), f(1) = 1

    这里数组taken的作用就是标记某个数是否被占用。

    在这个例子里面,要求第一个数,计算(10 - 1) / 5 + 1 = 2。

    表示这个数是所有未被占用的数里面从小到大第2个数,也就是2。

    再计算一下余数r = (10 - 1) % 5等于4

    如果r == 0说明后面的数没有了,跳出循环。

    否则m = r;

    继续下一轮循环

    这里m == 4,计算第二个数 (4 - 1) / 2 + 1 == 2。

    现在2已经被第一个数占用了,所以未被占用的第二个数就是3。

    后面依次类推。

     1 //#define LOCAL
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 using namespace std;
     6 
     7 int main(void)
     8 {
     9     #ifdef LOCAL
    10         freopen("2062in.txt", "r", stdin);
    11     #endif
    12 
    13     int n;
    14     bool taken[25];
    15     int b[25];
    16     long long m, a[25];
    17     a[1] = 1;
    18     for(int i = 2; i <= 20; ++i)
    19         a[i] = i * (a[i - 1] + 1);
    20 
    21     while(scanf("%d%I64d", &n, &m) == 2)
    22     {
    23         memset(taken, false, sizeof(taken));
    24         int i;
    25         long long r = 1;
    26         for(i = 1; i <= n; ++i)
    27         {
    28             b[i] = ((m - 1) / (a[n - i] + 1)) + 1;
    29             int j, k = 0;
    30             for(j = 1; j <= n; ++j)
    31             {
    32                 if(!taken[j])
    33                     ++k;
    34                 if(k == b[i])
    35                     break;
    36             }
    37             b[i] = j;
    38             taken[j] = true;
    39             r = (m - 1) % (a[n - i] + 1);
    40             if(r == 0)
    41                 break;
    42             m = r;
    43         }
    44         for(int j = 1; j < i; ++j)
    45             printf("%d ", b[j]);
    46         printf("%d
    ", b[i]);
    47     }
    48     return 0;
    49 }
    代码君
  • 相关阅读:
    Ckeditor(4.5.5) language 语言切换
    利用array_slice进行手动分页
    PHP API 接口访问之签名验证
    mysql外键的一些总结
    缺货置顶功能(类似功能可参考)
    [Exchange2013] 无法正常发送存入草稿箱 或者 只能发不能收
    [Exchange]2个不同域之间互发邮件
    [Citrix NetScaler] 简述
    [转载] cookie、JS记录及跳转到页面原来的位置
    [XenServer] XenServer修改IP 以及 root密码
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/3832909.html
Copyright © 2011-2022 走看看