1. 程式人生 > >dp練習(8)——數的劃分

dp練習(8)——數的劃分

結合 ddl 都是 ble 聯賽 限制 content 不同的 right

1039 數的劃分

2001年NOIP全國聯賽提高組

時間限制: 1 s 空間限制: 128000 KB 題目等級 : 黃金 Gold 題目描述 Description

將整數n分成k份,且每份不能為空,任意兩種劃分方案不能相同(不考慮順序)。
例如:n=7,k=3,下面三種劃分方案被認為是相同的。
1 1 5

1 5 1

5 1 1
問有多少種不同的分法。

輸入描述 Input Description

輸入:n,k (6<n<=200,2<=k<=6)

輸出描述 Output Description


輸出:一個整數,即不同的分法。

樣例輸入 Sample Input

7 3

樣例輸出 Sample Output

4

數據範圍及提示 Data Size & Hint

{四種分法為:1,1,5;1,2,4;1,3,3;2,2,3;}

貼出代碼:
#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n,k;
    cin >> n >> k;
    int dp[505][505];
    for(int i=1;i <= n;i++)
    {
        dp[i][
1] = 1; dp[i][i] = 1; } for(int i=1;i <= n;i++) { for(int j=1;j < i;j++) { dp[i][j] = dp[i-1][j-1] + dp[i-j][j]; } } cout << dp[n][k] << endl; return 0; }

代碼解釋:

首先分析第一段:

for(int i=1;i <= n;i++)
    {
        dp[i][
1] = 1; dp[i][i] = 1; }

dp[第幾個數][劃分幾次] 無論什麽數劃分1次的結果都是只有一種情況,無論什麽數劃分和他位數相同的數的結果只有一種情況。

然後分析第二段:

for(int i=1;i <= n;i++)
    {
        for(int j=1;j < i;j++)
        {
            dp[i][j] = dp[i-1][j-1] + dp[i-j][j];
        }
    }

這個我一開始也思考不明白,感覺和傳統的dp有點不同,結合了各個博客的解釋稍微理解了點。

主要思想:分為有1存在和沒有1存在兩種情況

有1存在:dp[i-1][j-1] 表示的是將i分為最小值為1的方案的總個數,例如,6(=7-1)分成2(=3-1)份可以分為{1,5}{2,4}{3,3},則7可以分為{1,5,1}{2,4,1}{3,3,1}【共3種】

沒有1存在:dp[i-j][j-1]]表示的是將i分為不包含1的方案的總個數,例如,4(=7-3)分成3份可以分為{1,1,2},則7可以分為{1+1,1+1,2+1}->{2,2,3}【共1種】註意下劃線部分

由此構成了如下的遞推式:

 dp[i][j] = dp[i-1][j-1] + dp[i-j][j];

dp練習(8)——數的劃分