1. 假设某卡牌类游戏里面,你搜集了 17 种卡牌,每种卡牌的攻击伤害率从小到大排列分别 为 1,4,9,… ,289,即 n 的平方(1<=n<=17,n 为正整数),并且每种卡牌的数量足够 多,现在请你计算出有多少种卡牌组合方式使得卡牌的总攻击率为 m(m<=500)比如 m=10, 那么有 4 种组合卡牌的方式,相同种卡牌可重复出现;
【分析】 此类问题属于组合计数问题,在组合数学中,最经典的问题就是给定n个不同类型的砝码(单个类型的砝码数不固定),求当给定一个值时,求解能够完成称重的所有组合数。而此类问题一般可通过“生成函数(母函数)”的方法来解决。但这种方法再实际编程过程中,往往需要求解出一个通向式。故在此,我们将选取另一种方法来解决该问题。
首先,定义函数: findNumber(E,n,energy) , 其中 n = Math.sqrt(E) ; 该函数表示当总攻击率为E时,采用前n种卡牌进行组合,最终能达到目标的组合数。而对于上述问题,可以分解为两个子问题:①使用前n-1种选择组成E的组合数 ②至少使用第n种选择一次时组成m的组合数。 这样问题就变得迎刃而解了。采用递归的方式,将上述子问题相加即可得到最终的结果。
以下为该问题的JAVA代码:
import java.util.Scanner;
public class Main {
public int findNumber(int E, int n, int[] energy) {
if(E == 0)
return 1;
if( E < 0 || n <= 0)
return 0;
return findNumber(E, n-1, energy) + findNumber(E - energy[n], n, energy);
}
public static void main(String[] args) {
int[] energy = new int[18];
for(int i=0; i<energy.length; i++) {
energy[i] = i*i;
}
Scanner sc = new Scanner(System.in);
int E = sc.nextInt();
Main m = new Main();
System.out.println(m.findNumber(E, (int)Math.sqrt(E), energy));
}
}
2.题目要求:
输入: 第一行三个数n,m,k,分别表示n个数,取m个,且m个中的任意两个位置差要大于等于K,接下来一行,有n个整数,表示序列上的每个数。
输出: 最大和
数据范围: n<=10000, m<=100,m<=n
Sample Input
4 2 2
3 4 -5 1
Sample Output
5