在百度贴吧Dota吧看到一道算法题,假设卡尔能召唤k种元素,并且身上同时能挂m个元素,则卡尔最多能搓出多少个技能?
题目特意指出,卡尔搓出什么技能仅取决于身上挂着的各种元素数目的比值,而与元素的排列顺序无关。
解这个题花了我一天的时间,惭愧,因为我是基于我昨天的思路开展的,而昨天的思路是错的。重新对题目进行形式化描述后,问题很快解决。
不过两种思路的基础是一样的,都是对题目进行正确的建模——针对每种元素进行讨论,而不是针对每个槽位——然后将建好的模型映射到递归模型上
#include <stdio.h>
#include <stdlib.h>
unsigned int skill(unsigned int elem_num, unsigned int slot_num){
int skill_num = 0;
int elem_i_slot_num = 0;
if (elem_num == 0){
return 0; //如果卡尔连一种元素都召唤不来,自然搓不出任何技能
}else if (elem_num == 1){
return 1; //当只能召唤一种元素时,卡尔身上就算同时能挂m个元素,也只能搓出一种技能
}
if (slot_num == 0){
return 1; //当代码运行到此处时,说明卡尔还能召唤1种以上的技能,但此时他身上已经挂满了元素,所以能搓出的技能已经是固定的一种
}else if (slot_num == 1){
return elem_num; //当卡尔身上只能挂一个元素时,就算能召唤k种元素,也只能搓出k种技能
}
//分情况讨论:
//如果已知第i种元素占0个槽位,则卡尔能搓出技能f(k,m)等于f(k-1, m);
//如果已知第i种元素占1个槽位,则卡尔能搓出的技能f(k,m)等于f(k-1, m-1),
//以此类推,将第i种元素的所有可能槽位占据情况累加起来,就得到了卡尔所有能搓出的技能,
//又因为技能跟元素排列顺序无关,所以总技能数就是
//f(k,m) = f(k-1, m) + f(k-1, m-1) + ... + f(k-1, 0)
for (elem_i_slot_num = 0; elem_i_slot_num <= slot_num; elem_i_slot_num++){
skill_num += skill(elem_num - 1, slot_num - elem_i_slot_num);
}
return skill_num;
}
int main()
{
unsigned int k, m;
printf("input elem num and slot num, seperated by a blank space\n");
scanf("%u %u", &k, &m);
printf("%u\n", skill(k, m));
return 0;
}