今天看到了一个捕鱼问题,觉得很不错,自己也跟着琢磨了半天,写了java的实现程序,现把问题叙述如下:
题目:20个桶,每个桶中有10条鱼,用网从每个桶中抓鱼,每次可以抓住的条数随机,每个桶只能抓一次,问一共抓到180条的排列有多少种 (也可求概率)
分析:1.我们要在20个桶中一共抓取180条鱼,每个桶能抓到鱼的条数为0-10,仔细想下,这个问题是可以分解成子问题的:假设我们在前i个桶中抓取了k(0<=k<=10*i)条鱼,那么抓取180条鱼的排列种数就等于在剩下的(20-i)个桶中抓取(180-k)条鱼的方法加上前i个桶中抓取k条鱼的方法。
2.换个思维,在实现上这个题目可以有更为简洁的方法,我们看看这个问题的对偶问题,抓取了180条鱼之后,20个桶中剩下了20条鱼,不同的抓取的方法就对应着这些鱼在20个桶中不同的分布,于是问题转化为将20条鱼分到20个桶中有多少中不同的排列方法(这个问题当然也等价于180条鱼分到20个桶中有多少种不同的方法)?其中,每个桶最多放10条,最少放0条。这样一转化,无论是用搜索还是DP,问题规模都缩小了很大一块。
java代码实现:
import java.util.Scanner;
public class fishing {
static Scanner obj;
static int [][]dp=new int[21][200];
int i,j,k;
public static void main(String []args){
int bucketN, fishN;
obj = new Scanner(System.in);
bucketN = obj.nextInt();
fishN = obj.nextInt();
for(int i = 0; i <= 10; ++i) /* 初始化合法状态 */
{
dp[1][i] = 1;
}
for(int i = 2; i <= bucketN; ++i) /* 从第二个桶开始 */
{
for(int j = 0; j <= fishN; ++j)
{
for(int k = 0; k <= 10 && j-k >= 0; ++k)
{
dp[i][j] += dp[i-1][j-k];
}
}
}
System.out.println(dp[bucketN][fishN]);
}
}
输入 两个值即可
总结:要把问题不断化为小问题去解决,即分治法,亦或从对立的角度去思考问题
出现的问题总结:1.二维数组初始化尽量用int [][] array = new int [10][10];
2.利用scanner类实现输入(以前没这方面的研究...好水,)利用nextInt()方法获取输入数值,或者可以利用字符流输入,利用split方法截取输入的参数
文章参考:http://www.ahathinking.com/archives/112.html