【OD真题】中秋分月饼
https://www.nowcoder.com/discuss/617792831947661312?sourceSSR=users
题目描述
中秋节,公司分月饼,m个员工,买了n个月饼,m<=n,每个员工至少分1个月饼,但可以分多个,单人分到最多月饼的个数是Max1,单人分到第二多月饼个数是Max2,Max1-Max2<=3,单人分到第n-1多月饼个数是Max(n-1),单人分到第n多月饼个数是Max(n),Max(n-1)-Max(n)<=3问有多少种分月饼的方法?
- 递归+回溯
public static int divide(int n, int m) {
int[] arr = new int[m];
for (int i = 0; i < m; i++) {
arr[i] = 1;
}
if (n == m){
return 1;
}
return backtrack(m, n-m, 0, arr);
}
private static int backtrack(int m, int k, int index, int[] arr) {
// 每个人都分配好了月饼时,看月饼是否分配完
if (index == m) {
if (k == 0){
return 1;
} else if (k > 0) {
return 0;
}else {
return 0;// k没有小于0的情况
}
}
// 月饼提前分配完,看是否满足差额限制
if (k == 0){
if (arr[index] >= arr[index - 1]-3){
return 1;
}else {
return 0;
}
}
int result =0;
// 还剩k个月饼要分配,已经分到index位置
for (int i = 1; i <= k; i++) {
int value = arr[index] + i;
// 当前位置,分配i个月饼满足条件则继续下个位置,否则直接返回0
if (index==0 || (index>0 && arr[index - 1] >= value && value >= arr[index - 1]-3)){
arr[index] += i;
// 递归
result += backtrack(m, k-i, index+1, arr);
// 回溯
arr[index] -= i;
}
}
return result;
}
- 动态规划
public static int divide2(int n, int m) {
int K = n-m;
int[][][] dp = new int[K+1][m+1][K+1];
for (int i = 0; i < K+1; i++) {
// 只有一个人时,月饼全部分给这个人是一种方案
dp[i][1][i] = 1;
}
for (int i = 1; i <= K; i++) {
for (int j = 2; j <= m; j++) {
// 枚举最后一个员工分到的月饼数量
for (int k = 0; k <= i; k++) {
// 因为相同分配方案只是顺序不一样,也认为是同一个,所以我们假设分配结果中,员工获得月饼数是递减的
// 如果第j位员工获取k个月饼,那么第j-1个员工的月饼数只能是k,k+1,k+2,k+3这四种情况
dp[i][j][k] = dp[i - k][j - 1][k];
if (k+1<K+1){
dp[i][j][k] += dp[i - k][j - 1][k+1];
}
if (k+2<K+1){
dp[i][j][k] += dp[i - k][j - 1][k+2];
}
if (k+3<K+1){
dp[i][j][k] += dp[i - k][j - 1][k+3];
}
}
}
}
return Arrays.stream(dp[K][m]).sum();
}
浙公网安备 33010602011771号