首页 > 其他分享 >31. 分月饼

31. 分月饼

时间:2024-12-31 18:58:27浏览次数:3  
标签:月饼 int 31 list current allocations 分配

简介
一个考察动态规划的机试题的数学模型建立,和两种思路的取舍

题目
公司分月饼,m个员工,买了n个月饼,m <= n,每个员工至少分一个月饼,但是也可以分到多个,单人分到最多月饼的个数是Max1,单人分到第二多月饼个数是Max2。

但需要满足Max1-Max2 <= 3,单人分到第n-1多月饼个数是Max(n-1),单人分到第n多月饼个数是Max(n), 想要满足Max(n-1) - Max(n) <= 3,问有多少种分月饼的方法?

输入描述:

每一行输入m,n,表示m个员工,n个月饼,m <=n

输出描述:

输出有多少种分法

示例1:

输入

2 4

输出

2

说明

4=1+3

4=2+2

注意:1+3和3+1要算成同一种分法

示例2:

输入

3 5

输出

2

说明

5=1+1+3

5=1+2+3

示例3:

输入

3 12

输出

6

说明

满足要求的6种分法:

1、12 = 1 + 1 + 10 (Max1=10, Max2=1,不满足Max1-Max2 <= 3的约束)

2、12 = 1 + 2 + 9 (Max1=9,Max2=2,不满足Max1-Max2 <= 3的约束)

3、12 = 1 + 3 + 8 (Max1=8,Max2=3,不满足Max1-Max2 <= 3的约束)

4、12 = 1 + 4 + 7 (Max1=7,Max2=4,Max3=1, 满足要求)

5、12 = 1 + 5 + 6 (Max1=6,Max2=5,Max3=1, 不满足要求)

6、12 = 2 + 2 + 8 (Max1=8,Max2=2,不满足要求)

7、12 = 2 + 3 + 7 (Max1=7,Max2=3,不满足要求)

8、12 = 2 + 4 + 6 (Max1=6,Max2=4,Max3=2, 满足要求)

9、12 = 2 + 5 + 5 (Max1=5,Max2=2 满足要求)

10、12 = 3 + 3 + 6 (Max1=6,Max2=3 满足要求)

11、12 = 3 + 4 + 5 (Max1=5,Max2=4,Max3=3 满足要求)

12 = 4 + 4 + 4 (Max1=4,满足要求)
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/qq_45763343/article/details/135894692

一、问题分析

首先读题,仔细看描述中的内容,发现需求是

1.公司分月饼,m个员工,买了n个月饼,m<=n,

2.每个员工至少分一个月饼,但是也可以分到多个,

3.单人分到最多月饼的个数是Max1,单人分到第二多月饼个数是Max2。

4.但需要满足Max1 - Max2 <= 3,单人分到第n - 1多月饼个数是Max(n - 1),

5.单人分到第n多月饼个数是Max(n),想要满足Max(n - 1) - Max(n) <= 3,问有多少种月饼的分法

6.输入描述:第一行输入m,n,表示m个员工,n个月饼,m<=n

7.输出描述:输出有多少种分法

二、解题思路

1.首先员工的数量小于等于月饼的数量,所以不用担心有人分不到

2.Max(n-1)-Max(n) <= 3证明员工之间不能存在发月饼数量差超过3个的情况

比如有一个人分到4个月饼,如果其他人最少分到的月饼是8个的话,这种分法不成立

3.我们看一下例子再理解一下问题

比如有2个员工,4块月饼的时候

因为最少每个人分一个月饼,然后说明中的分法是没有剩下的月饼的,月饼要全部分完

所以我们相当于2个人分2块月饼

分法是两个人一人一块或者一个人拿两块,一共两种分法(1+3和3+1算一种分法—,就是说一个人拿三块一个人拿一块和一个人拿一块一个人拿三块我们不做区分)

4.再看一下示例2:

3个员工,5块月饼

因为每个人至少分一块,所以相当于3个人分2块

方法是一个人一块一个人一块,一个人没有

或者一个人两块,两个人没有

一共两种方法

5.再看一下示例3:

3个员工,12块月饼

每个人分至少一块,还剩下9块

3个人分9块

分法是一个人1块一个人1块一个人7块(不成立)

或者一个人1块一个人2块一个人6块(不成立)

或者一个人1块一个人3块一个人5块(成立)

或者一个人1块一个人4块一个人4块(成立)

或者一个人2块一个人3块一个人4块(成立)

或者一个人0块,一个人3块一个人6块(成立)

或者一个人2块,一个人2块一个人5块(成立)

或者一个人3块,一个人3块一个人3块(成立)

6.首先定义两个结构体,Allocation和AllocationList

Allocation结构体用于表示一种月饼的分配方案,其中values是一个动态分配的整数数组指针,用于存储每个员工分到的月饼数量,size表示该分配方案中员工的数量(也就是values的长度)。

typedef struct Allocation {

int* values;

int size;

} Allocation;

AllocationList结构体用于存储所有的分配方案,它包含一个Allocation类型的指针allocations,指向存储所有分配方案的数组,count表示当前已经存储的分配方案的数量,capacity表示allocations数组的容量(即最多能存储多少种分配方案),通过这种方式可以方便地对分配方案列表进行动态管理,当分配方案数量超过容量时进行动态扩展。

typedef struct AllocationList {

Allocation* allocations;

int count;

int capacity;

} AllocationList;

7.然后我们声明一个函数用于初始化分配方案列表,首先为结构体本身分配内存,然后初始化count为0,表示初始时没有存储任何分配方案,设定一个初始的capacity(这里设置为10,可根据实际需求调整),接着为allocations指针分配内存,用于存储具体的分配方案数组,最后返回创建好的列表结构体指针。

AllocationList* createAllocationList() {

AllocationList* list = (AllocationList*)malloc(sizeof(AllocationList));

if(list == NULL) {

perror("内存分配失败");

exit(1);

}

list->count = 0;

list->capacity = 10;

list->allocations = (Allocation*)malloc(list->capacity * sizeof(Allocation));

if(list->allocations == NULL) {

perror("内存分配失败");

free(list);

exit(1);

}

return list;

}

8.然后我们声明一个addAllocation函数用于向已有的分配方案列表中添加一种新的分配方案。添加之前,先检查分配方案的数量count是否已经达到了列表的容量capacity,如果达到了,就动态扩展列表的容量(通过重新分配更大内存空间,将原有数据复制过去的方式),然后将新的分配方案添加到allocations数组中,并将count加1,表示列表中又多了一种分配方式。

void addAllocation(AllocationList* list, Allocation allocation) {

if(list->count >= list->capacity) {

// 如果容量不够,动态扩展容量

int new_capacity = list->capacity * 2;

Allocation* new_allocations = (Allocation*)malloc(new_capacity * sizeof(Allocation));

if(new_allocations == NULL) {

perror("内存分配失败");

exit(1);

}

for(int i = 0; i < list->count; i++) {

new_allocations[i] = list->allocations[i];

}

free(list->allocations);

list->allocations = new_allocations;

list->capacity = new_capacity;

}

list->allocations[list->count++] = allocation;

}

9.然后我们声明一个函数用于释放整个分配方案列表所占用的内存,它首先遍历allocations数组中每个Allocation结构体中的values指针所指向的动态分配的整数数组内存(因为每个分配方案中的员工分到的月饼数数组是动态分配的,需要单独释放),然后释放allocations数组本身的内存以及AllocationList结构体的内存,确保没有内存泄露。

void freeAllocationList(AllocationList* list) {

for(int i = 0; i < list->count; i++) {

free(list->allocations[i].values);

}

free(list->allocations);

free(list);

}

10.之后我们声明递归辅助函数,用于计算月饼的分配方案并将满足条件的方案添加到结果列表中。需要的参数有剩余月饼数量n,总员工数m,上一个员工分到的月饼数last,当前每个员工分配到的月饼数量数组current,当前分配方案的员工数量current_size,结果列表result

void partitionHelper(int n, int m, int last, int* current, int current_size, AllocationList* result) {

首先判断当前分配方案的员工数量current_size是否已经达到了总员工数m,如果达到了,并且剩余月饼数n也刚好为0,说明找到了一种满足条件的分配方案,此时创建一个新的Allocation结构体,为其values数组分配内存,将当前分配方案中每个员工分到的月饼数(存储在current数组中)复制到values数组中,设置size为m,然后通过addAllocation函数将这个新的分配方案添加到结果列表result中。

if(current_size == m) {

if(n == 0) {

Allocation allocation;

allocation.values = (int*)malloc(m * sizeof(int));

if(allocation.values == NULL) {

perror("内存分配失败");

exit(1);

}

for(int i = 0; i < m; i++) {

allocation.values[i] = current[i];

}

allocation.size = m;

addAllocation(result, allocation);

}

return;

}

接着计算当前员工可以分配到的月饼数的范围,start表示起始值,如果当前是第一个员工(current_size == 0),则从0开始,否则取上一个员工分到的月饼数(current[current_size - 1])和0中的较大值作为起始值,保证满足每人至少1个月饼且相邻差值不超过3的条件;end表示结束值,如果当前是第一个员工,则最多可以分到n/m个月饼(平均分配的大致上限),否则取剩余月饼数n和last + 3(last是上一个员工分到的月饼数,要保证差值不超过3)中的较小值作为结束值。

int start = current_size == 0 ? 0 : (current[current_size - 1] > 0 ? current[current_size - 1] : 0);

int end = current_size == 0 ? n / m : (n < last + 3 ? n : last + 3);

最后通过for循环从start到end的每个可能的月饼数i,将其分配给当前员工(存储在current[current_size]中),然后递归调用partitionHelper函数,更新剩余月饼数为n - i,继续计算下一个员工的分配情况,这样通过递归不断地探索所有可能的分配方案并添加到结果列表中。

for(int i = start; i <= end; i++) {

current[current_size] = i;

partitionHelper(n - i, m , i, current, current_size + 1, result);

}

}

11.然后是partition函数,parition函数作为对外的接口函数,首先调用createAllocationList函数创建一个空的分配方案结果列表result,然后为存储当前正在构建的分配方案的数组current分配内存,接着调用partitionHelper函数开始递归计算分配方案,将计算得到的满足条件的方案添加到result列表中,计算完成后释放current数组的内存,最后返回包含所有分配方案的结果列表result.

AllocationList* partition(int n, int m) {

AllocationList* result = createAllocationList();

int* current = (int*)malloc(m * sizeof(int));

if(current == NULL) {

perror("内存分配失败");

exit(1);

}

partitionHelper(n - m, m, 0, current, 0, result);

free(current);

return result;

}

12.然后是主函数,首先定义了月饼总数n和员工数m,然后读取数据,然后调用partition函数计算分配方案列表,输出分配方案的数量以及每个具体的分配方案内容(或者不输出),最后通过freeAllocationList函数释放结果列表所占用的内存,确保程序没有内存泄露,结束整个程序。

int main() {

int n, m;

scanf("%d %d", &m, &n);

AllocationList* result = partition(n, m);

printf("%d\n", result->count);

freeAllocationList(result);

return 0;

}

三、具体步骤

使用的语言是C 

#include <stdio.h>
#include <stdlib.h>

// 结构体用于存储一种分配方案
typedef struct Allocation {
    int* values;
    int size;
} Allocation;

// 结构体用于存储所有分配方案的列表
typedef struct AllocationList {
    Allocation* allocations;
    int count;
    int capacity;
} AllocationList;

// 初始化分配方案列表
AllocationList* createAllocationList() {
    AllocationList* list = (AllocationList*)malloc(sizeof(AllocationList));
    if (list == NULL) {
        perror("内存分配失败");
        exit(1);
    }
    list->count = 0;
    list->capacity = 10;  // 初始容量,可以根据需要调整
    list->allocations = (Allocation*)malloc(list->capacity * sizeof(Allocation));
    if (list->allocations == NULL) {
        perror("内存分配失败");
        free(list);
        exit(1);
    }
    return list;
}

// 向分配方案列表中添加一种分配方案
void addAllocation(AllocationList* list, Allocation allocation) {
    if (list->count >= list->capacity) {
        // 如果容量不够,动态扩展容量
        int new_capacity = list->capacity * 2;
        Allocation* new_allocations = (Allocation*)malloc(new_capacity * sizeof(
                                          Allocation));
        if (new_allocations == NULL) {
            perror("内存分配失败");
            exit(1);
        }
        for (int i = 0; i < list->count; i++) {
            new_allocations[i] = list->allocations[i];
        }
        free(list->allocations);
        list->allocations = new_allocations;
        list->capacity = new_capacity;
    }
    list->allocations[list->count++] = allocation;
}

// 释放分配方案列表占用的内存
void freeAllocationList(AllocationList* list) {
    for (int i = 0; i < list->count; i++) {
        free(list->allocations[i].values);
    }
    free(list->allocations);
    free(list);
}

// 辅助函数,用于递归地计算分配方案
void partitionHelper(int n, int m, int last, int* current, int current_size,
                     AllocationList* result) {
    if (current_size == m) {
        if (n == 0) {
            Allocation allocation;
            allocation.values = (int*)malloc(m * sizeof(int));
            if (allocation.values == NULL) {
                perror("内存分配失败");
                exit(1);
            }
            for (int i = 0; i < m; i++) {
                allocation.values[i] = current[i];
            }
            allocation.size = m;
            addAllocation(result, allocation);
        }
        return;
    }

    int start = current_size == 0 ? 0 : (current[current_size - 1] > 0 ?
                                         current[current_size - 1] : 0);
    int end = current_size == 0 ? n / m : (n < last + 3 ? n : last + 3);
    for (int i = start; i <= end; i++) {
        current[current_size] = i;
        partitionHelper(n - i, m, i, current, current_size + 1, result);
    }
}

// 主函数,用于启动分配方案的计算并返回结果列表
AllocationList* partition(int n, int m) {
    AllocationList* result = createAllocationList();
    int* current = (int*)malloc(m * sizeof(int));
    if (current == NULL) {
        perror("内存分配失败");
        exit(1);
    }
    partitionHelper(n - m, m, 0, current, 0, result);
    free(current);
    return result;
}

int main() {
    int m, n;
    scanf("%d", &m);
    scanf("%d", &n);
    AllocationList* result = partition(n, m);
    printf("%d\n", result->count);
    // for (int i = 0; i < result->count; i++) {
    //     for (int j = 0; j < result->allocations[i].size; j++) {
    //         printf("%d ", result->allocations[i].values[j]);
    //     }
    //     printf("\n");
    // }
    freeAllocationList(result);
    return 0;

标签:月饼,int,31,list,current,allocations,分配
From: https://blog.csdn.net/bingw0114/article/details/143765740

相关文章

  • 静力学FEM12.31
    1.静力学方程考虑图所示变截面弹性杆的静态响应。这是线性应力分析或线弹性问题的一个例子,我们需要求杆内的应力分布σ(x)。应力由物体的变形产生,而变形由物体内各点的位移u(x)表征。位移导致用ε(x)表示的应变;应变是一个无量纲变量。杆受到分布力b(x)或集中力作用。这个力可能......
  • [241231]阿普米司特抗银屑病的同时辅助抗真菌感染
    已知真菌定植/感染可能参与触发或加重斑块状银屑病.抗IL-17和TNFi可能增加真菌感染风险.一项探索性研究通过70例难治部位(头皮,指甲,间擦部/外生殖器)银屑病患者接受阿普米司特治疗前以及治疗1年过程中(允许局部真菌感染入组并继续抗真菌治疗),监测真菌定植/局部真菌感染以及......
  • 12.31安全检测(软硬件面试)&信息专员
    EN、IEC安全标准介绍EN:欧洲标准(例如EN303645,针对物联网设备的网络安全要求)。身份鉴别:强身份认证、防止未授权(强密码)远程访问控制:鉴权、强密码安全更新和补丁:接收补丁更新数据保护:数据传输存储加密隐私保护:保护用户个人数据、不收集不必要信息IEC标准:国际电工委员会(IEC)的......
  • leetcode 3186. 施咒的最大总伤害
    3186.施咒的最大总伤害这道题相比 740.删除并获得点数  ,区别是这道题的元素值可以特别大,所以就不能开大数组。没做出来......
  • 【日记】明年或许会是非常重要的一年(1231 字)
    正文时间紧迫,简单写写。今天下午全国上下计划财务处条线的人都加班。从14:30开始,一直等通知到15:30多才开始做,说是系统只开放到17:00,但是因为找数据、找会计科目、计算会计等式、冲账这一套下来挺花时间也蛮难的,所以我们折腾到了16:30左右才搞完。部分支行还涉及......
  • 2024-2025-1 20241311 《计算机基础与程序设计》第十四周学习总结
    学期2024-2025-1学号20241311《计算机基础与程序设计》第十四周学习总结作业信息这个作业属于哪个课程<班级的链接>2024-2025-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>2024-2025-1计算机基础与程序设计第一周作业这个作业的目标<写上具体......
  • 2024-2025-1 20241319 《计算机基础与程序设计》第十四周学习总结
    作业信息这个作业属于哪个课程2024-2025-1-计算机基础与程序设计这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK14这个作业的目标《C语言程序设计》第13章作业正文https://www.cnblogs.com/wchxx/p/18639513**教材学习内容总结1.......
  • 学期2024-2025-1学号202413177 《计算机基础与程序设计》第十四周学习总结
    学期2024-2025-1学号202413177《计算机基础与程序设计》第十四周学习总结作业信息这个作业属于哪个课程<班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(如2024-2025-1计算机基础与程序设计第一周作业)这个作业的目标<写上具......
  • 20241313刘鸣宇《计算机基础与程序设计》第14周学习总结
    2024-2025-120241313《计算机基础与程序设计》第14周学习总结作业信息这个作业属于哪个课程<班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(如2024-2025-1计算机基础与程序设计第一周作业)这个作业的目标<写上具体方面>......
  • 2024-2025-1 20241314 《计算机基础与程序设计》第十四周学习总结
    2024-2025-120241314《计算机基础与程序设计》第十四周学习总结作业信息这个作业属于哪个课程<班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>2024-2025-1计算机基础与程序设计第十四周作业作业正文正文教材学习内容总......