劃分數
阿新 • • 發佈:2018-12-23
劃分數 挑戰上的題
***************************************************************************************
注意是不超過
1、定義dp[i][j]=j的i的劃分總數 j的i劃分表示的意義為 j固定,i可以取到1-i。
2、遞推公式 dp[i][j]=dp[i][j-i]+dp[i-1][j];
3、分類討論:
1.j >= i時,dp[i][j] = dp[i-1][j] ( j的i-1劃分,相當於當前位取0的全部情況 ) + dp[i][j-i](當前位不取0,先把每一個置為1,再將剩下的j-i分下去);
2.j < i時,dp[i][j] = dp[i-1][j]; 當前位只能取0。
例題:
郭姐最近很無聊,於是就開始分石頭。郭姐有n顆石頭,她要把石頭分成m堆,每堆至少有一個石子,她想知道有多少種分法
輸入描述
-
2個整數,n和m(m <= n <= 20)。
輸出描述
-
一個整數,表示種數
樣例輸入 7 3 樣例輸出 4
來源 2016年中北大學新生賽
提示 由於石頭都是一樣的,若僅僅只是順序不同,那還是同一種分法,比如把7分成3堆,(1,1,5)和(1,5,1)是同一種
注意是剛好m堆,每堆至少一個石子
上述提到的公式是適用於不超過m即空堆是小於m的數即可 所以注意最後答案是(看程式碼)
#include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<iostream> #include<stdlib.h> using namespace std; const int inf=0x3f3f3f3f; const int maxn=1000000; int dp[50][50]; int main(){ int n,m; cin>>n>>m; dp[0][0]=1; for(int i=1;i<=m;i++){ for(int j=0;j<=n;j++){ if(j>=i){ dp[i][j]=dp[i][j-i]+dp[i-1][j]; }else dp[i][j]=dp[i-1][j]; } } int ans=dp[m][n]-dp[m-1][n];//注意 cout<<ans<<endl; return 0; }
牛客 放蘋果 一樣的題https://www.nowcoder.com/questionTerminal/bfd8234bb5e84be0b493656e390bdebf
不過是不超過M堆的情況;
#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
int dp[50][50];
int main(){
int n,m;
cin>>m>>n;
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
if(j>=i)
dp[i][j]=dp[i][j-i]+dp[i-1][j];
else
dp[i][j]=dp[i-1][j];
}
}
int ans=dp[n][m];
cout<<ans<<endl;
return 0;
}
遞迴也可以寫
牛客該題下討論有詳解,感興趣可以去學一下