原問題:20 個桶每桶 10 條魚,每桶抓一次,隨機抓取數量,求抓滿 180 條的方案數。
抓 180 條 ⇔ 剩 20 條。問題等價於:將 20 條魚分配到 20 個桶,每桶 0~10 條,有多少種分配方法?
狀態定義:dp[i][j] = 前 i 個桶放 j 條魚的方法數
初始狀態:dp[1][k] = 1 (0 ≤ k ≤ 10)
轉移方程:
dp[i][j] = Σ dp[i-1][j-k] (0 ≤ k ≤ 10 且 j-k ≥ 0)
void CatchFish() {
int dp[21][200] = {0};
int bucketN = 20, fishN = 20; // 對偶問題:20桶分20魚
// 初始化第1個桶
for (int i = 0; i <= 10; ++i) dp[1][i] = 1;
// 填表
for (int i = 2; i <= bucketN; ++i) {
for (int j = 0; j <= fishN; ++j) {
for (int k = 0; k <= 10 && j-k >= 0; ++k) {
dp[i][j] += dp[i-1][j-k];
}
}
}
printf("%d\n", dp[bucketN][fishN]);
}
自頂向下遞歸同樣正確,但函數調用開銷大,DP 迭代更高效。本質是有放回的有限容量組合數問題,也可用生成函數求解。