POJ1037A decorative fence(动态规划+排序计数+好题)

http://poj.org/problem?id=1037

题意:输入木棒的个数n,其中每个木棒长度等于对应的编号,把木棒按照波浪形排序,然后输出第c个;

分析:总数为i跟木棒中第k短的木棒 就等于总数为i-1中比这一根短的方案数 + 和比这一根长的方案数;最后用一个三维数组表示成c[i][k][up/down],c[i][k][up]表示i跟木棒中第k短的下一个比他长的方案数,就可以枚举每一个比他长的数相加;

排列计数问题:求一个排列中第几个是什么?

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5
 6 using namespace std;
 7 #define UP 0
 8 #define DOWN 1
 9 const int MAX = 30;
10 long long c[MAX][MAX][2];
11 int seq[MAX],used[MAX];
12 void Init(int n)
13 {
14     memset(c, 0, sizeof(c));
15     c[1][1][UP] = c[1][1][DOWN] = 1;
16     for(int i = 2; i <= n; i++)  //个数
17     {
18         for(int k = 1; k <= i; k++)  //第i短
19         {
20             for(int N = k; N < i; N++)
21             {
22                 //这个循环为什么k而不是k+1开始呢?
23                 //因为c[i][k][UP]是指以i个木棒中第k短开头的上升木棒,那么下一个的总数就是i-1,那是i-1中第几短呢,除掉前面的那个k,比他长的就是第k到i-1(除去k后,比他稍微长点的就成了第k短)
24                 c[i][k][UP] +=  c[i - 1][N][DOWN];
25             }
26             for(int M = 1; M <= k - 1; M++)
27             {
28                 //这个没啥影响
29                 c[i][k][DOWN] += c[i - 1][M][UP];
30             }
31         }
32     }
33 }
34 void print(int n, long long cc)
35 {
36     long long  skipped = 0;
37     int No = 0;
38     long long  oldValue = skipped;
39     memset(used, 0, sizeof(used));
40     for(int i = 1; i <= n; i++)
41     {
42         int k;
43         No = 0;
44         oldValue = skipped;
45         for(k = 1; k <= n; k++)
46         {
47             oldValue = skipped;//用oldvalue保留每一次最先开始的次数,然后skipped不断算跳跃的方案数
48             if(used[k] == 0)
49             {
50                 No++;
51                 if(i == 1)
52                 {
53                     skipped += c[n][No][UP] + c[n][No][DOWN];
54                 }
55                 else
56                 {
57                     if(k > seq[i - 1] && (i <= 2 || seq[i - 2] > seq[i - 1]))
58                     {
59                         skipped += c[n - i + 1][No][DOWN];
60                     }
61                     else if(k < seq[i - 1] && (i <= 2 || seq[i - 2] < seq[i - 1]))
62                     {
63                         skipped += c[n - i + 1][No][UP];
64                     }
65                 }
66                 if(skipped >= cc) //跳跃的方案数比给定的大,那就跳出循环,如果比cc小就在改变oldvalue值
67                     break;
68             }
69         }
70         used[k] = true;
71         seq[i] = k;
72         skipped = oldValue;
73     }
74     for(int i = 1; i < n; i++)
75         printf("%d ", seq[i]);
76     printf("%d\n", seq[n]);
77 }
78 int main()
79 {
80     int t,n;
81     long long C;
82     Init(20);
83     scanf("%d", &t);
84     while(t--)
85     {
86         scanf("%d%I64d", &n,&C);
87         print(n, C);
88     }
89     return 0;
90 }

时间: 2024-11-05 16:27:29

POJ1037A decorative fence(动态规划+排序计数+好题)的相关文章

POJ1037 A decorative fence 【动态规划】

A decorative fence Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 6489   Accepted: 2363 Description Richard just finished building his new house. Now the only thing the house misses is a cute little wooden fence. He had no idea how to m

ACM/ICPC算法训练 之 数学很重要-浅谈“排列计数” (DP题-POJ1037)

这一题是最近在看Coursera的<算法与设计>的公开课时看到的一道较难的DP例题,之所以写下来,一方面是因为DP的状态我想了很久才想明白,所以借此记录,另一方面是看到这一题有运用到 排列计数 的方法,虽然排列计数的思路简单,但却是算法中一个数学优化的点睛之笔. Poj1037  A decorative fence 题意:有K组数据(1~100),每组数据给出总木棒数N(1~20)和一个排列数C(64位整型范围内),N个木棒长度各异,按照以下条件排列,并将所有可能结果进行字典序排序 1.每一

算法导论-- 线性时间排序(计数排序、基数排序、桶排序)

线性时间排序 前面介绍的几种排序,都是能够在复杂度nlg(n)时间内排序n个数的算法,这些算法都是通过比较来决定它们的顺序,这类算法叫做比较排序 .下面介绍的几种算法用运算去排序,且它们的复杂度是线性时间. -------------------------------------- 1.计数排序 计数排序采用的方法是:对每个元素x,去确定小于x的元素的个数,从而就可以知道元素x在输出数组中的哪个位置了. 计数排序的一个重要性质是它是稳定的,即对于相同的两个数,排序后,还会保持它们在输入数组中的

nyist oj 540 奇怪的排序(水题)

奇怪的排序 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描述 最近,Dr. Kong 新设计一个机器人Bill.这台机器人很聪明,会做许多事情.惟独对自然数的理解与人类不一样,它是从右往左读数.比如,它看到123时,会理解成321.让它比较23与15哪一个大,它说15大.原因是它的大脑会以为是32与51在进行比较.再比如让它比较29与30,它说29大. 给定Bill两个自然数A和B,让它将 [A,B] 区间中的所有数按从小到大排序出来.你会认为它如何排序? 输入 第一

codevs 1487 大批整数排序(水题日常)

时间限制: 3 s 空间限制: 16000 KB 题目等级 : 黄金 Gold 题目描述 Description !!!CodeVS开发者有话说: codevs自从换了评测机,新评测机的内存计算机制发生变化 计算内存的时候会包括栈空间 swap空间 这题的2M是单指内存空间... 十分十分抱歉 抱歉 !!! 现在有一大批(总数不超过10000000个)1到10之间的整数,现在请你从小到大进行排序输出. (测试数据将超过11MB.) 输入描述 Input Description 第一行表示将下排序

排序计数类题目小结

考虑到每次出哒哒哒操作,最少多少次操作使数组有序这一类题我都错的很惨,小小地总结一下 1.交换相邻位置的点->求逆序对(火柴排队,10.30noip模拟赛T1),有效的操作一定使得逆序对减少一个 2.交换任意位置->转化为置换(10.30noip模拟赛T1),置换内交换只需要置换中点个数次 3.每次可以把一个数扔到最前面->(HDU5500,noip模拟赛11.12T1)官方题解: 把这题的模型简化一下,有一个1→n的排列形成的数列,我们要用最少的操作次数把这个数列排序,每次操作都是把一

[NOIP 2014复习]第二章:动态规划——NOIP历届真题回顾

序列型动态规划 1.Wikioi 1058 合唱队形 题目描述 Description N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2-,K,他们的身高分别为T1,T2,-,TK,  则他们的身高满足T1<...<Ti>Ti+1>->TK(1<=i<=K). 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形. 输入

【算法导论-学习笔记】以线性时间增长的排序——计数排序

计数排序是一种能够达到运行时间能够线性时间θ(n)的排序算法.在排序算法里算是最快的算法之一,当然,他有很强烈的前提.下面开始介绍一下技术排序(Counting Sort). 算法思想 计数排序假设n个输入元素中的每一个都是介于0到k之间的整数,此处k为某个整数.这样可以用一个数组C[0..k]来记录待排序数组里元素的数量.当k=O(n)时,计数排序的运行时间为θ(n). 注:关于C[0..k],用键值对描述的话,待排序元素是键,相同元素的个数是值.例:待排序数组<2,3 , 6,4 , 1 ,

hdu 5701 中位数计数 思路题

中位数计数 Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 909    Accepted Submission(s): 346 Problem Description 中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数. 现在有n个数,每个数都是独一无二的,求出每个数在多少个包