zoukankan      html  css  js  c++  java
  • POJ1037 A decorative fence

    题目来源:http://poj.org/problem?id=1037

    题目大意:

      用长度从1至N的N块木板来围成一个围栏。要求是围栏成波浪形,即每块木板要么比它两边的木板都低要么比它两边的木板都高。现对所有符合要求的排列方式进行排序。排序规则是从第一块木板开始计算,越短的排名越前,前面的相等,向后依次比较。(即字典序)先给出N和一个指定的数字i,求符合要求的排列中的第i个。

    输入:第一行一个正整数表示测试用例数。接下每行为一个测试用例,含两个数字分别表示N和i。

    输出:指定的木板排列方案。


    Sample Input

    2
    2 1
    3 3

    Sample Output

    1 2
    2 3 1

    本题遍历显然是不可行的,会超时。解决思路是求给定前缀的排列有多少种,然后查表找出指定的序列。即求出以1开头的序列有多少种,以1开头的序列里第二个是2的有多少种...依次类推,建立起各种前缀排列数的表。求表的过程由DP实现。

    所用的DP方法很巧妙。实际有两个dp表。一个up表,dp[len][i](up)表示len根木板的排列里,第一根木棍长度为i,第二根木棍比第一根长的方案数(M形)。同时还有一个dp[len][i](down)表示len根木板的排列里,第一根为i,第二根比第一根短的方案数(W形)。

    dp[len][i].down = sigmaj(j<i)(dp[len-1][j].up);

    dp[len][i].up=sigmaj(i<=j<=len-1)(dp[len-1][j].down).

    对这两个式子的一个疑问是:当选定了i作为len长的序列的第一根木棍后,剩下的问题跟原问题不一样了,因为木棍不再是连续排列的。其实事实上,问题的本质还是一样的,我们可以把剩余的木棍中比i长的长度都减1。不过按这样计算出dp表后,在查表求指定序列时要注意把减去的长度复原。

      1 //////////////////////////////////////////////////////////////////////////
      2 //        POJ1037 A decorative fence
      3 //        Memory: 264K        Time: 32MS
      4 //        Language: C++        Result: Accepted
      5 //////////////////////////////////////////////////////////////////////////
      6 
      7 #include <iostream>
      8 using namespace std;
      9 
     10 struct Plan {
     11     long long up;
     12     long long down;
     13 };
     14 
     15 int n;
     16 long long c;
     17 Plan dp[21][21];
     18 bool used[21];
     19 int index;
     20 long long leftCnt;
     21 
     22 void init() {
     23     dp[1][1].up = dp[1][1].down = 1;
     24     for (int len = 2; len <= 20; ++len) {
     25         for (int j = 1; j <= len; ++j) {
     26             for (int k = 1; k < j; ++k) {
     27                 dp[len][j].down += dp[len-1][k].up;
     28             }
     29             for (int k = j; k < len; ++k) {
     30                 dp[len][j].up += dp[len - 1][k].down; 
     31             }
     32         }
     33     }
     34 }
     35 int find(int k) {
     36     int cnt = 0;
     37     for (int i = 1; i <= n; ++i) {
     38         if (used[i] == false) {
     39             ++cnt;
     40         }
     41         if (cnt == k) {
     42             return i;
     43         }
     44     }
     45 }
     46 
     47 void process() {
     48     bool direction;
     49     int first;
     50     leftCnt = c;
     51     memset(used, false, sizeof(used));
     52     for (first = 1; first <= n; ++first) {
     53         if (dp[n][first].down >= leftCnt) {
     54             direction = false;//down
     55             break;
     56         }
     57         leftCnt -= dp[n][first].down;
     58         if (dp[n][first].up >= leftCnt) {
     59             direction = true;//up 
     60             break;
     61         }
     62         leftCnt -= dp[n][first].up;
     63     }
     64     used[first] = true;
     65     cout << first;
     66     int last = first;
     67     for (int len = n - 1; len > 0; --len) {
     68         int j;
     69         if (direction == true) {
     70             for (j = last; j < len; ++j) {
     71                 if (dp[len][j].down >= leftCnt) {
     72                     break;
     73                 }
     74                 leftCnt -= dp[len][j].down;
     75             }
     76         } else {
     77             for (j = 1; j < last; ++j) {
     78                 if (dp[len][j].up >= leftCnt) {
     79                     break;
     80                 }
     81                 leftCnt -= dp[len][j].up;
     82             }
     83         }
     84         int t = find(j);
     85         cout << " " << t;
     86         used[t] = true;
     87         last = j;
     88         direction = direction ? false : true;
     89     }
     90     cout << endl;
     91 }
     92 
     93 int main() {
     94     int k;
     95     cin >> k;
     96     init();
     97     while (k--) {
     98         cin >> n >> c;
     99         process();
    100     }
    101     system("pause");
    102     return 0;
    103 }
    View Code
  • 相关阅读:
    数据库生成连续编号 前几位为零
    C#中图片与BASE64码互相转换
    C#基于Socket的CS模式的完整例子
    一个公共类
    HttpCookie 操作Cookie
    C#打包SQL数据库部署安装
    <转>遍历 进程 内的内核对象
    《windows核心编程》–Windows内存体结构(二)
    《windows核心编程》–Windows内存体结构(一)
    《windows 核心编程》 探索虚拟内存
  • 原文地址:https://www.cnblogs.com/dengeven/p/3231267.html
Copyright © 2011-2022 走看看