hrbust 1216/哈理工oj 1216 數的劃分【dp】
阿新 • • 發佈:2019-01-28
數的劃分 | ||||||
|
||||||
Description | ||||||
將整數n分成k份,且每份不能為空,任意兩份不能相同(不考慮順序)。 例如:n=7,k=3,下面三種分法被認為是相同的。 1,1,5; 1,5,1; 5,1,1; 問有多少種不同的分法。 |
||||||
Input | ||||||
有多則測試資料。 對於每組測試資料,僅有一行,包括兩個整數n,k (6<n<=200,2<=k<=6)。 | ||||||
Output | ||||||
對於每組測試資料,輸出一個整數,即不同的分法。 | ||||||
Sample Input | ||||||
7 3 | ||||||
Sample Output | ||||||
4 | ||||||
Hint | ||||||
輸入: 7 3 輸出:4 {四種分法為:1,1,5; 1,2,4; 1,3,3; 2,2,3;} |
||||||
Source | ||||||
NOIp2001高中組 | ||||||
Recommend | ||||||
黃李龍 |
第一眼看到這個題,最基礎的思路有兩個,一個是dp,估計推出不來,一個是搜尋找解,因為資料不是很大,也許交一發超時實在不行還可以打表。
然後默默的dfs,也解出了樣例。但是在測試資料的時候整個人都崩潰了、輸入 200 6的時候,等待是很漫長的、、、、、剪枝無果,dp找思路。找啊找啊找思路,無果,百度數的劃分,最後找到了明確的解釋。
dp的思路是這樣形成的:
考慮兩個極端,一個是不要1的情況,一個是至少要一個1的情況(也可以理解為要1的情況)、
如果我們規定dp【i】【j】表示資料i分成j個數據有多少方法的話,我們的dp【i-1】【j-1】就是至少要一個1的情況(要1的情況)、那麼dp【i-j】【j】就是不要1的情況。
後邊這半句話可能理解起來費點勁。假如我們拿樣例來說話,根據剛剛的思路寫出這樣的等式:
dp【7】【3】=dp【4】【3】+dp【6】【2】、假設我們這裡知道dp【4】【3】和dp【6】【2】。後邊的dp【6】【2】很好理解,在6的基礎上加1,同時相當於7分解成6和1、但是前邊我們怎麼理解呢?我們這樣理解這個問題:7個小球放在3個盒子裡,不要有任何一個盒子只有一個小球,這個時候我們可以先拿出3個小球,然後任意分配4個小球到三個盒子裡,然後我們手裡的三個小球,每一個盒子裡都放下一個小球,這樣就形成了不會有哪個盒子只有一個小球的情況,所以這裡我們就能得到這樣的動態規劃方程:
dp【i】【j】=dp【i-j】【j】+dp【i-1】【j-1】;
最後上完整的AC程式碼:
#include <stdio.h>
#include <string.h>
using namespace std;
int dp[205][7];
int main()
{
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= 205; i++)
{
for (int j = 1; j <= 6; j++)
{
if (i >= j)
{
dp[i][j] = dp[i-j][j] + dp[i-1][j-1];
}
}
}
int n, k;
while (~scanf("%d%d", &n, &k))
{
printf("%d\n", dp[n][k]);
}
return 0;
}