整數劃分(小結劃分數如何dp)

2021-08-26 05:50:27 字數 3048 閱讀 5274

原**小結劃分數如何dp

1.hdu 1028 整數劃分

首先,我們引進乙個小小概念來方便描述吧,dp[n][m]是把自然數劃劃分成所有元素不大於m的分法,例如: 

當n=4,m=1時,要求所有的元素都比m小,所以劃分法只有1種:; 

當n=4,m=2時,只有3種,,; 

當n=4,m=3時,只有4種,,,; 

當n=4,m=5時,只有5種,,,,; 

從上面我們可以發現:當n==1||m==1時,只有一種分法; 

當n < m時,由於分法不可能出現負數,所以dp[n][m]=dp[n][n]; 

當n==m時,那麼就得分析是否要分出m這乙個數,如果要分那就只有一種,要是不分,那就是把n分成不大於m-1的若干份;即dp[n][n]=1+dp[n][n-1]; 

當n>m時,那麼就得分析是否要分出m這乙個數,如果要分那就,}時n-m的分法dp[n-m][m],要是不分,那就是把n分成不大於m-1的若干份;即dp[n][n]=dp[n-m][m]+dp[n][m-1];

**:

#includeusing namespace std;

#define maxn 121

int dp[maxn][maxn]=;

int main()

}int n;

while(scanf("%d",&n)!=eof)printf("%d\n",dp[n][n]);

return 0;

}

ps:這題也可以母函式做,參考: 

2.cdoj 1307 abcde

題意: 

在數電中,有一種碼,類似bcd碼這種玩意兒 

第i位如果為1的話,那麼ans+=a[i],a[i]是這一位的位權 

然後現在給你乙個n,問你一共有多少種碼可以表示1~n的所有數呢? 

1,1,2和2,1,1視作一樣。

解法: 

dp預處理 

首先考慮這個東西,如果不視作一樣的話,就很簡單了

dp[i]表示當前和為i的方案數,顯然這個玩意兒能夠一直轉移到2i-1去。(比如5,你轉移到最大的肯定是3,不然就無法表示出1,2,3,4,5每個數了,這很顯然)

由於視作一樣,那麼我們只要維護乙個當前的最大值就好了,保證這個序列是遞增的,這樣就都不會一樣了。

dp[i][j]表示現在和為i,最大值為j的方案數有多少。

轉移方程: 

dp[i][j]=(dp[i−1][j−1]+dp[i−j][j])

前者表示由沒有最大值j轉移過來,後者表示從有最大值j轉移過來

#include using namespace std;

typedef long long ll;

const int mod = 1e9+7;

long long dp[5010][5010];

long long ans[5010];

int main()

}int t;

scanf("%d", &t);

while(t--)

return 0;

}

3.687c the values you can make 

題意:給n個各有價值的硬幣,要從它們中選出若干個組合成面值k,而要求的是各個方案裡這些選出的硬幣能組合出來的面值有哪些

dp[i][j][k]表示到第i個硬幣,和為j,組成面值為k這種情況是否存在。 

要用滾動陣列寫,不然要爆記憶體

詳細可以看題解: 

**:

#include using  namespace  std;

#define ff first

#define ss second

#define pb push_back

#define ll long long

#define mod 1000000007

#define ull unsigned long long

#define mst(ss,b) memset(ss,b,sizeof(ss));

#define pl(x) cout << #x << "= " << x << endl;

const int inf=0x3f3f3f3f;

const int n=505;

bool dp[2][n][n];//第i個 和為j 組成面額為k

int n, k, c[n], cnt;

int ans[n];

int main()}}

for(int i=0; i<=k; i++)

printf("%d\n", cnt);

for(int i=1; i<=cnt; i++)printf("%d ", ans[i]);

return 0;

}

4.51nod 1201 整數劃分

思路: 

dp[i][j]表示i這個數劃分成j個數的情況數。 

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

前者表示將i - 1劃分為j個數,然後j個數都+1 還是不重複 

後者表示將i - 1劃分為j - 1個數,然後j - 1個數都+1,再加上1這個數 

普通的dp是o(n^2)的,但是可以發現1 + 2 + … + m = n , (1 + m)m = n 2,j只要遍歷sqrt(n * 2)個就好了。所以複雜度為o(n*sqrt(n*2))

#include using  namespace  std;

#define mod 1000000007

templatevoid read(t&num)

const int n=5e4+10;

int dp[n][351], n;

int main()

}} int ans = 0;

for(int i = 1; i < 350; i++)

ans = (ans + dp[n][i]) % mod;

printf("%d\n", ans);

return 0;

}

整數劃分 劃分數(DP動態規劃)

給你乙個正整數n,讓你計算出n的m劃分有幾種方法。思路 定義dp i j 為i的j劃分,即將i劃分為j個數字之和的方案數。1 當j i時,此時,劃分個數不超過i,此時是正常的劃分。劃分的結果一定只有兩種型別 一種是j個數字,都大於0。另一種是有0,即不夠劃分j個,用0來湊的。j個數字中存在0的,其實...

整數劃分(數的m劃分)

includeusing namespace std int f int n,int m n代表數字,m代表n的m劃分 int main 方式二 動態規劃 dp i j 表示i的j次劃分的情況種數 狀態轉移方程為dp i j dp i j j dp i 1 j 1 1.dp i 1 j 1 表示劃分...

整數劃分(劃分dp)總結

寫了幾個題發現整數劃分是一類題,而不是一道題。具體題型 1 n相同元素放入m個相同的盤子 盤子允許為空 例題 放蘋果 poj 1664設dp i j 為 j 個元素放入i個盤子轉移方程 dp i j dp i 1 j 新新增乙個盤子,盤子為空 dp i j dp i j i i個盤子 各取出乙個 2...