题目描述
将整数 n 分成 k 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如: n=7 , k=3 ,下面三种分法被认为是相同的。
1,1,5
1,5,1
5,1,1
问有多少种不同的分法。
输入格式:
n,k
输出格式:
1个整数,即不同的分法。
输入样例
7 3
输出样例
4
虽然正解是DP,但还是搜索又好写,又易懂
dfs代码:(暴力枚举不解释)
#include<stdio.h> int ans; void dfs(int n,int k,int i) { if(k==0 || n==0) { if(k==0 && n==0) ans++; return ; } for(i;i<=n;++i) dfs(n-i,k-1,i); } int main() { int n,k; scanf("%d%d",&n,&k); dfs(n,k,1); printf("%d",ans); }
DP做法:
个人认为,能不用DP就不用DP(至少我这样的新手是推不出公式的)
据学长的指导,将情况分为有 1 和没有 1 的情况
如样例
有1:{1,1,5};{1,2,4};{1,3,3}
没1:{2,2,3}
可见,最终的答案可以表示为——ans=“有1”的情况+"没1"的情况
我们用一个 f[i][j] 表示 数值为 i ,j 种分法
有1的情况:f[i-1][j-1]
没1的情况:f[i-j][j]
如样例
7 3 有1的情况与6 2的分法相同
1 1 5 1 5
1 2 4 2 4
1 3 3 3 3
7 3 没1的情况与4 3的分法相同
2 2 3 2 2
So f[i][j]=f[i-1][j-1]+f[i-j][j]
正解的DP:
#include<stdio.h> int f[201][7]; int main() { int n,k; scanf("%d%d",&n,&k); f[0][0]=1; for(int i=1;i<=n;++i) for(int j=1;j<=k;++j) if(i>=j){ f[i][j]=f[i-1][j-1]+f[i-j][j]; } printf("%d",f[n][k]); return 0; }
还有一种该题的变型——放苹果
题意类似,不同之处在于可以放“0”,一个暴搜就可以做的
代码如下
#include<stdio.h> int divide(int lev,int plat) { if(lev==0 || lev==1 || plat==1) return 1; if(lev<plat) return divide(lev,lev); return divide(lev-plat,plat)+divide(lev,plat-1); } int main() { int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); printf("%d ",divide(n,m)); } return 0; }
但其实正解还是DP