博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 2062 Subset sequence
阅读量:4466 次
发布时间:2019-06-08

本文共 1801 字,大约阅读时间需要 6 分钟。

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

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

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

以n=3,m=10举例:

11 21 2 31 31 3 222 12 1 32 32 3 133 13 1 23 23 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 
3 #include
4 #include
5 using namespace std; 6 7 int main(void) 8 { 9 #ifdef LOCAL10 freopen("2062in.txt", "r", stdin);11 #endif12 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\n", b[i]);47 }48 return 0;49 }
代码君

 

转载于:https://www.cnblogs.com/AOQNRMGYXLMV/p/3832909.html

你可能感兴趣的文章
第一堂java web课
查看>>
操作系统简介
查看>>
第1周小组博客作业--1703班06组
查看>>
vue项目中icon图标的完美引入
查看>>
C语言指针
查看>>
Java的安装
查看>>
0920 JSON数据 蓝懿
查看>>
Azure Cosmos DB 使用费用参考
查看>>
【嵌入式开发】写入开发板Linux系统-模型S3C6410
查看>>
C# 子线程与主线程通讯方法一
查看>>
006——修改tomacat的编码
查看>>
《C程序设计语言》笔记 (八) UNIX系统接口
查看>>
git常用命令
查看>>
Android必知必会-获取视频文件的截图、缩略图
查看>>
(转)理解Bitblt、StretchBlt与SetDIBitsToDevice、StretchDibits
查看>>
python之路-基础篇-第七周
查看>>
高性能队列Disruptor系列2--浅析Disruptor
查看>>
ViurtualBox配置虚拟机Linux的网络环境
查看>>
VLC 媒体播放器
查看>>
勿忘国耻2018/09/18
查看>>