挑战程序设计竞赛笔记_计数DP划分数_P67

( ╯□╰ ),菜鸡看了一上午才看懂orz

1.学了这么多天DP,对递推关系也有了一些认识:在想这个递推关系的时候先不要顾及边界,只想递推关系中的一个节点和之前的节点之间的关系就好,递推的初始状态之后再另外想。

2.划分数这个题,(0,0,2)也是一种正确的划分。这个在后面的推导过程中是可以看出来的。

3.可以先看一下这个链接上的讲解:点击打开链接

开始敲黑板了!!!

4.一定要结合实例理解,这是理解这些东西的最好的工具,别问我是怎么知道的。代码注释里有我用书上的实例推导的一个结果,代码先了解一下,主要是后面的注释

 

#include <cstdio>
int n, m, M;
const int MAX_M = 10000;
const int MAX_N = 1000;
int dp[MAX_M + 1][MAX_N + 1];
void print(int row, int col)
{
    printf("i/j |");
    for (int i = 0; i <= col; i++)
        printf("%4d", i);
    printf("\n-----");
    for (int i = 0; i <= col; i++)
        printf("----");
    for (int i = 0; i <= row; i++)
    {
        printf("\n%3d |", i);
        for (int j = 0; j <= col; j++)
            printf("%4d", dp[i][j]);
    }
}
int main()
{
    freopen("E:/My/input.txt", "r", stdin);
    scanf("%d%d%d", &n, &m, &M);
    printf("n = %d, m = %d, M = %d\n", n, m, M);
    dp[0][0] = 1;
    for (int i = 1; i <= m; i++)
        for (int j = 0; j <= n; j++)
            if (j - i >= 0)
                dp[i][j] = (dp[i - 1][j] + dp[i][j - i]) % M;
            else
                dp[i][j] = dp[i - 1][j];
    print(m, n);
    return 0;
}

/*
n = 4, m = 3, M = 10000
i/j |   0   1   2   3   4
-------------------------
  0 |   1   0   0   0   0
  1 |   1   1   1   1   1
  2 |   1   1   2   2   3
  3 |   1   1   2   3   4

i/j |   0            1            2                    3                            4
----------------------------------------------------------------------------------------------------------------------
  0 |   1            0            0                    0                            0
  1 |   1{(0)}       1{(1)}       1{(2)}               1{(3)}                       1{(4)}
  2 |   1{(0,0)}     1{(0,1)}     2{(0,2),(1,1)}       2{(0,3),(1,2)}               3{(0,4),(1,3),(2,2)}
  3 |   1{(0,0,0)}   1{(0,0,1)}   2{(0,0,2),(0,1,1)}   3{(0,0,3),(0,1,2),(1,1,1)}   4{(0,0,4),(0,1,3),(0,2,2),(1,1,2)}
*/

如上图,拿dp[3][4]来说。红框之内的东西便是dp[i - 1][j],发现了吧,就是在dp[2][4]的每个元素前面加了个0。而黑框内的就是dp[i][j - i],即dp[3][1],每个值减了1。要想严密的分解dp的元素,可以把dp[3][4]中的()分解为两种,一种是以0打头的(也就是dp[i - 1][j]加了个0,以0打头说明这串数中至少有一个0,所以)另一种就是一个0也没有的,这两类数对应上面的两个不同颜色的框,所以也就能理解了为什么作者这么分了:dp[i][j] = dp[i - 1][j] + dp[i][j - i]。

 

接下来是初始状态的赋值,这题i = 0着实令人有些费解,所以可以直接从i=1开始赋值,把i = 1这行的都赋值为1,memset当然不行了所以直接循环赋值,循环的时候直接从i=2开始。

NICE...

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值