C語(yǔ)言?深入理解動(dòng)態(tài)規(guī)劃之計(jì)數(shù)類DP
寫在前面
之前講過(guò)背包問(wèn)題,線性DP,區(qū)間DP,不知道大家忘了嗎,這次是計(jì)數(shù)類DP
石子合并


老規(guī)矩,先畫圖。
思路:把1,2,3, … n分別看做n個(gè)物體的體積,這n個(gè)物體均無(wú)使用次數(shù)限制,問(wèn)恰好能裝滿總體積為n的背包的總方案數(shù)(完全背包問(wèn)題變形)
初值問(wèn)題:
求最大值時(shí),當(dāng)都不選時(shí),價(jià)值顯然是 0
而求方案數(shù)時(shí),當(dāng)都不選時(shí),方案數(shù)是 1(即前 i 個(gè)物品都不選的情況也是一種方案),所以需要初始化為 1
即:for (int i = 0; i <= n; i ++) f[i][0] = 1;
等價(jià)變形后: f[0] = 1
狀態(tài)計(jì)算:
f[i][j]表示前i個(gè)整數(shù)(1,2…,i)恰好拼成j的方案數(shù)
求方案數(shù):把集合選0個(gè)i,1個(gè)i,2個(gè)i,…全部加起來(lái)
f[i][j] = f[i - 1][j] + f[i - 1][j - i] + f[i - 1][j - 2 * i] + …;
f[i][j - i] = f[i - 1][j - i] + f[i - 1][j - 2 * i] + …;
因此 f[i][j]=f[i−1][j]+f[i][j−i]; (這一步類似完全背包的推導(dǎo))
樸素做法
// f[i][j] = f[i - 1][j] + f[i][j - i]
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 7, mod = 1e9 + 7;
int f[N][N];
int main() {
int n;
cin >> n;
for (int i = 0; i <= n; i ++) {
f[i][0] = 1; // 容量為0時(shí),前 i 個(gè)物品全不選也是一種方案
}
for (int i = 1; i <= n; i ++) {
for (int j = 0; j <= n; j ++) {
f[i][j] = f[i - 1][j] % mod; // 特殊 f[0][0] = 1
if (j >= i) f[i][j] = (f[i - 1][j] + f[i][j - i]) % mod;
}
}
cout << f[n][n] << endl;
}
等價(jià)變形
// f[i][j] = f[i - 1][j] + f[i][j - i]
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 7, mod = 1e9 + 7;
int f[N];
int main() {
int n;
cin >> n;
f[0] = 1; // 容量為0時(shí),前 i 個(gè)物品全不選也是一種方案
for (int i = 1; i <= n; i ++) {
for (int j = i; j <= n; j ++) {
f[j] = (f[j] + f[j - i]) % mod;
}
}
cout << f[n] << endl;
}
上面是完全背包問(wèn)題的解法,再來(lái)看看不用完全背包問(wèn)題求解

狀態(tài)計(jì)算:分兩部分
- 這j個(gè)數(shù)中存在最小值為1的數(shù) 先去掉這一個(gè)1,其他部分表示為總和為i-1,恰好由j-1個(gè)數(shù)f[i-1][j-1]
- 這j個(gè)數(shù)中存在的最小值都>1 j個(gè)數(shù)都>1,讓j個(gè)數(shù)都-1,求總和為j-i,由j個(gè)數(shù)的方案表示:f[i-j][j]
綜上所述:f[i][j] = f[i - 1][j - 1] + f[i - j][j];
//非背包做法
//狀態(tài)表示:f[i][j] 所有總和是i,并且恰好可以表示成j個(gè)數(shù)的和的方案
#include <bits/stdc++.h>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int n;
int f[N][N];
int main()
{
cin >> n;
f[0][0] = 1;
for (int i = 1; i <= n; i ++ )
//i最多表示成i個(gè)數(shù)的和,因此j<=i
for (int j = 1; j <= i; j ++ )
f[i][j] = (f[i - 1][j - 1] + f[i - j][j]) % mod;
int res = 0;
for (int i = 1; i <= n; i ++ ) res = (res + f[n][i]) % mod;
cout << res << endl;
return 0;
}
到此這篇關(guān)于C語(yǔ)言 深入理解動(dòng)態(tài)規(guī)劃之計(jì)數(shù)類DP的文章就介紹到這了,更多相關(guān)C語(yǔ)言 計(jì)數(shù)類DP內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語(yǔ)言 深入探究動(dòng)態(tài)規(guī)劃之區(qū)間DP
- C語(yǔ)言深入探究動(dòng)態(tài)規(guī)劃之線性DP
- C語(yǔ)言動(dòng)態(tài)規(guī)劃多種背包問(wèn)題分析講解
- C語(yǔ)言動(dòng)態(tài)規(guī)劃點(diǎn)殺dp算法LeetCode炒股習(xí)題案例解析
- C語(yǔ)言動(dòng)態(tài)規(guī)劃之背包問(wèn)題詳解
- C語(yǔ)言矩陣連乘 (動(dòng)態(tài)規(guī)劃)詳解
- C語(yǔ)言使用DP動(dòng)態(tài)規(guī)劃思想解最大K乘積與乘積最大問(wèn)題
相關(guān)文章
如何通過(guò)UltraEdit解析BMP文件內(nèi)部結(jié)構(gòu)(BMP位圖基礎(chǔ))
我們先打開畫圖隨便畫一幅圖并采用24位bmp圖像格式保存,就得到了一張24位真彩色的位圖,下面我們來(lái)詳細(xì)分析bmp位圖的各個(gè)組成部分,感興趣的朋友跟隨小編一起看看吧2021-08-08
記逆向小白的第一次vbsedit 9爆破及內(nèi)存補(bǔ)丁制作過(guò)程
這篇文章主要介紹了記逆向小白的第一次vbsedit 9爆破及內(nèi)存補(bǔ)丁制作過(guò)程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
解析VC中創(chuàng)建DLL,導(dǎo)出全局變量,函數(shù)和類的深入分析
本篇文章是對(duì)VC中創(chuàng)建DLL,導(dǎo)出全局變量,函數(shù)和類進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C語(yǔ)言實(shí)現(xiàn) 數(shù)據(jù)類型占多少字節(jié)指針占多少字節(jié)
這篇文章主要介紹了 C語(yǔ)言 數(shù)據(jù)類型占多少字節(jié)指針占多少字節(jié)的實(shí)例代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
C語(yǔ)言中sizeof和strlen的區(qū)別詳解
這篇文章主要介紹了C語(yǔ)言中sizeof和strlen的區(qū)別,文中有通過(guò)代碼示例和相關(guān)例題給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06
Qt實(shí)現(xiàn)發(fā)送HTTP請(qǐng)求的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何通過(guò)Qt實(shí)現(xiàn)發(fā)送HTTP請(qǐng)求,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-03-03
C語(yǔ)言中for循環(huán)問(wèn)題(一個(gè)小坑需注意)
這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中for循環(huán)問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

