簡單整數劃分(遞迴法+動態規劃法)
阿新 • • 發佈:2019-01-09
整數劃分:
所謂整數劃分,就是將一個數n寫成正整數相加的形式,如3可以劃分為1+1+1,1+2,3等三種情況,而f(n,m)則表示,劃分數中最大的數小於m時n的劃分。如f(3,2)就是1+1+1,1+2兩種。
遞迴法:
根據n和m的情況,有如下幾種情況
1.當n == 1或m == 1時,都只有一種劃分,其中n==1時,只有一種劃分{1},只有m == 1時,只有一種劃分{1,1,1.....,1};即n個1。
2.由於劃分中沒有負數,所以當n < 1或m < 1時,都只有0種劃分。
3.當n < m時,由於沒有負數,所以f(n,m)就相當於f(n,n);
4.當n == m時,可以分為兩種情況:
(1).劃分中有n即只有{n}一種情況。
(2).劃分中沒有n即劃分中最大值小於等於n-1,即n對於n-1的所有劃分。
所以綜上,n == m時,f(n,n) == f(n,n-1)+1;
5.當n > m時,可以分為兩種情況:
(1).劃分中包含最大值m的情況,即{m,{x1,x2.....}},而在{x1,x2.....},也就是n-m中同樣可能大於m,所以為n-m對於m的劃分,即f(n-m,m);
(2).劃分中不包含m,同情況4,所有值比m小,即f(n,m-1);
綜上,f(n-m,m)+f(n,m-1)。
程式碼如下:
#include <bits/stdc++.h> using namespace std; int query(int n,int m) { if(n == 1||m == 1) return 1; if(n < 1||m < 1) return 0; if(n < m) return query(n,n); if(n == m) return query(n,m-1)+1; if(n > m) return query(n-m,m)+query(n,m-1); } int main() { int n; while(~scanf("%d",&n)) { cout<<"遞迴:"<<query(n,n)<<endl; } return 0; }
動態規劃法:
在遞迴法中的1,2情況都可以直接通過初始化dp陣列來進行處理,而情況3,4,5則轉換成動態轉移方程就可以了。
轉移方程:dp[n][m] += dp[i][j-1]+dp[i-j][j];
(當i-j < j時)dp[n][m] += dp[i][j-1]+dp[i-j][i-j];
#include <bits/stdc++.h> using namespace std; const int N = 100; int main() { int n; int dp[550][550]; dp[1][1] = 1; for(int i = 2;i <= N; i++){dp[i][1] = 1;dp[i][i] = 1;} for(int i = 2;i <= N; i++) { for(int j = 2;j <= i; j++) { if(i-j < j) dp[i][j] += dp[i][j-1]+dp[i-j][i-j]; else dp[i][j] += dp[i][j-1]+dp[i-j][j]; } } while(~scanf("%d",&n)) cout<<"dp:"<<dp[n][n]<<endl; return 0; }