宁波大学2019院赛 nbuoj 2080 洛谷p1025 数的划分
链接:http://www.nbuoj.com/v8.83/Problems/Problem.php?pid=2820
链接:https://www.luogu.org/problem/P1025
题意:将整数nn分成kk份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
思路一:可开for暴力,在搜索的过程中进行剪枝,并且可以计算得,最小的数不会大于200/6,即n/k,可以在第一层循环里修改:for(int i=1;i<=n/k;i++)
//保证i<=j<=k<=o<=p<=q的同时,如果i+j+k+o+p+q==n,则cnt++ for(int i=1;i<=200;i++) { for(int j=i;i+j<=200;j++) { for(int k=j;i+j+k<=200;k++) { for(int o=k;i+j+k+o<=200;o++) { for(int p=o;i+j+k+o+p<=200;p++) { int q=200-i+j+k+o+p; if(q>=p)cnt++; } } } } }
思路二:dp,dp[i][j]表示i分成j堆有几种分法
转移方程:当i>j时,dp[i][j]=dp[i-j][j]+dp[i-1][j-1],否则dp[i][j]=0
①k堆里至少有一堆是1,dp[i][j]=dp[i-1][j-1]
②k堆里每堆都大于1,dp[i][j]=dp[i-j][j]
终止条件:i=1或j=1或j=i时,dp[i][j]=1
#include<bits/stdc++.h> using namespace std; int main() { int dp[220][10]={0},n,k; cin>>n>>k; for(int i=1;i<=n;i++) { for(int j=1;j<=k&&j<=i;j++) //j>i时肯定不能保证每堆都有数 { if(i==1||j==1||j==i){dp[i][j]=1;continue;} //这三个可以由dp[0][0]=1代替...why? dp[i][j]=dp[i-j][j]+dp[i-1][j-1]; } } cout<<dp[n][k]<<endl; return 0; }