『题目』:
一个袋子里面有n个球,每个球上面都有一个号码(拥有相同号码的球是无区别的)。如果一个袋子是幸运的当且仅当所有球的号码的和大于所有球的号码的积。
例如:如果袋子里面的球的号码是{1, 1, 2, 3},这个袋子就是幸运的,因为1 + 1 + 2 + 3 > 1 * 1 * 2 * 3。你可以适当从袋子里移除一些球(可以移除0个,但是别移除完),要使移除后的袋子是幸运的。现在让你编程计算一下你可以获得的多少种不同的幸运的袋子。
Input
第一行输入一个正整数n(n ≤ 1000)
第二行为n个数正整数xi(xi ≤ 1000)
Output
输出可以产生的幸运的袋子数
『输入输出』:
输入 | 输出 |
---|---|
3 1 1 1 | 2 |
4 1 1 2 3 | 6 |
『题解』:
这道题可以换个思路来想,假设一个袋子里有 N l N^l Nl 个种类的球,每个种类有 N g l N^l_g Ngl 个,任意的从不同种类的球(先排序)中取一定个数,使得球的编号加起来的和比球的编号乘起来的和要大。这个想法就很简单了,但是要剪枝,因为如果编号乘起来都比加起来大,后面没有搜索的必要了。至于为什么可以这样剪枝可以参考这篇博客,写得很清楚了,我是靠感觉出来的。
『注意』:
HashMap效率很低,尽量转为数组映射
『实现』:
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* Author:
* Gavinjou大笨象
* Date:
* 2019-05-11
* Description:
* 深搜递归
*/
public class Main {
//统计重复球数
private static Map<Integer,Integer> countMap;
//球的个数
private static int N;
//一共有多少种情况满足
private static int sum;
//唯一的编号有多少个
private static int[] uninum;
//每个数字的个数
private static int[] numNum;
//总共的唯一个数
private static int sizeN;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
countMap = new HashMap<Integer, Integer>();
while (sc.hasNext())
{
int i;//索引
sum = 0;
//初始化map
countMap.clear();
//读取要读的楸树
N = sc.nextInt();
for(i = 0;i < N;i++)
{
int tmp = sc.nextInt();
if(countMap.containsKey(tmp))
{
//统计当前数字重复的个数
countMap.put(tmp,countMap.get(tmp) + 1);
}
else
{
countMap.put(tmp,1);
}
}
sizeN = countMap.size();
uninum = new int[sizeN];
numNum = new int[sizeN];
i = 0;
for(Integer item : countMap.keySet())
{
uninum[i] = item;
i++;
}
Arrays.sort(uninum);
for(i = 0;i < sizeN ;i++)
{
numNum[i] = countMap.get(uninum[i]);
}
findSum(0,0,1);
System.out.println(sum);
}
}
private static void findSum(int level,long addSum,long mulSum)
{
if(level == sizeN)
{
//这个就是幸运数字
if(addSum > mulSum)
{
//如果加的数字大于乘起来的数字
sum++;
}
return ;
}
//剪枝优化
if (addSum !=0 && mulSum != 1 && mulSum > addSum ) return;
for(int i = 0;i <= numNum[level]; i++)
{
//当前数字选择这么多个,然后将结果乘起来和加起来有多大
findSum(level + 1,
addSum + uninum[level] * i,
mulSum*myPow(uninum[level],i)
);
}
}
private static long myPow(int base,int index)
{
long ans = 1;
for(int i = 0; i < index ; i++)
{
ans *= base;
}
return ans;
}
}