zoukankan      html  css  js  c++  java
  • ACM/ICPC 之 DP-整数划分问题初探 (POJ1221)

      写下这道题的原因很简单= =,因为这一题的状态转移方程不好找,另一方面,我看到很多针对这一题写的解题报告都把累加状态说得模棱两可,甚至直接说成了一个单一状态,弄得本是菜鸟的我硬生生折磨了一上午画了几个10*10的表才想出来(各种表思路还不一样= =||)


      题意:对整数N(N<250)进行划分,划分成单峰回文序列,题目给出K组N,然后求出相应总序列数目。

      例如:

      1: (1)

      2: (2), (1 1)

      3: (3), (1 1 1)

      4: (4), (1 2 1), (2 2), (1 1 1 1)

      5: (5), (1 3 1), (1 1 1 1 1)

      6: (6), (1 4 1), (2 2 2), (1 1 2 1 1), (3 3), (1 2 2 1), ( 1 1 1 1 1 1)

      7: (7), (1 5 1), (2 3 2), (1 1 3 1 1), (1 1 1 1 1 1 1)

      8: (8), (1 6 1), (2 4 2), (1 1 4 1 1), (1 2 2 2 1), (1 1 1 2 1 1 1), ( 4 4),

           (1 3 3 1), (2 2 2 2), (1 1 2 2 1 1), (1 1 1 1 1 1 1 1);

      解题思路:

        由于给出整数最大可到100+,我们可以想象一下100的整数划分之后的情况数绝对是一个很大的数字了。如果一 一枚举并进行判断无疑会TLE。

        但我们可以得出一种递推关系,例如 2.3.4.5.4.3.2 这种由23划分出的序列只要左右加上1就变成了 1.2.3.4.5.4.3.2.1 ,换成2就成为 2.2.3.4.5.4.3.2.2也就是说  27和25划分的部分序列可以根据23划分的部分序列来递推得到。

        既然有递推关系且我们可以知道上述单个状态是无后效性的,那么我们就可以用动态规划来完成这一递推

        我们简单假设A划分出的序列a1,a2,a3,a2,a1 可推出 由B划分的序列a0,a1,a2,a3,a2,a1,a0

        ps: 其中A = B - 2*a0

         那么我们递推的两个序列只需要满足a0<=a1即可

        我们用DP[A][a1]将A划分出的序列两端数字>=a1的总序列数作为一种状态,这样我们可以得到DP[B][a0]的全部序列

                            A中两端数大于i的总序列数

                                 |

        因此我们可以找到一个状态转移方程:dp[n][i] = dp[n-i*2][i] + dp[n][i+1];

                           |             |

                      B中两端数>=i的总序列       B中两端数 >= i+1 的总序列数

            因此最终Code为:

          

     1 //UNIMODAL PALINDROMIC DECOMPOSITIONS
     2 //整数划分 -> 单峰回文序列
     3 //二维DP-状态转移方程挺难想的,要以整数划分后得到的单峰回文序列两端数字>=i为一个状态
     4 //Memory:664K Time:0 Ms
     5 #include<iostream>
     6 #include<cstdio>
     7 #include<cstring>
     8 using namespace std;
     9 #define MAX 251
    10 long long dp[MAX][MAX];    //dp[n][i]代表整数为n进行划分时,两端处数字>=i的总情况数
    11 void DP()
    12 {
    13     for (int i = 1; i < MAX; i++)
    14         dp[i][i] = 1;
    15     for (int i = 1; i < MAX; i++)
    16         for (int j = i - 1; j >= 1; j--)
    17         {
    18             dp[i][j] = dp[i][j + 1];
    19             if (i - j * 2 == 0)    //刚好划分完
    20                 dp[i][j]++;
    21             else if (i - j * 2 >= j)    //可以继续划分
    22                 dp[i][j] += dp[i - j * 2][j];    //将i-j*2划分后且两端>=j的状态总数 转移给 i划分后两端为j的状态
    23         }
    24 }
    25 int main()
    26 {
    27     DP();
    28     int n;
    29     while (scanf("%d", &n), n)
    30         printf("%d %lld
    ", n, dp[n][1]);
    31     return 0;
    32 }
    小墨原创

                                  

    他坐在湖边,望向天空,她坐在对岸,盯着湖面
  • 相关阅读:
    jqueryeasyui1.2.3学习
    继续干IT的十个理由
    设计模式建造者模式(Builder Pattern)
    一段不错的视频
    第十一章:配置和安全IntelliMorph
    第十一章:配置和安全许可和配置
    物理库存和财务库存浅析
    第十一章:配置和安全概述
    IE6 双倍边距的解决方法
    asp实现关键词不区分大小写搜索并高亮显示
  • 原文地址:https://www.cnblogs.com/Inkblots/p/4791870.html
Copyright © 2011-2022 走看看