DP30 求骰子能凑成给定和的组合数 Dice Throw @geeksforgeeks

Given n dice each with m faces, numbered from 1 to m, find the number of ways to get sum X. X is the summation of values on each face when all the dice are thrown.

The Naive approach is to find all the possible combinations of values from n dice and keep on counting the results that sum to X.

This problem can be efficiently solved using Dynamic Programming (DP).

Let the function to find X from n dice is: Sum(m, n, X)
The function can be represented as:
Sum(m, n, X) = Finding Sum (X - 1) from (n - 1) dice plus 1 from nth dice
               + Finding Sum (X - 2) from (n - 1) dice plus 2 from nth dice
               + Finding Sum (X - 3) from (n - 1) dice plus 3 from nth dice
                  ...................................................
                  ...................................................
                  ...................................................
              + Finding Sum (X - m) from (n - 1) dice plus m from nth dice

So we can recursively write Sum(m, n, x) as following
Sum(m, n, X) = Sum(m, n - 1, X - 1) + 
               Sum(m, n - 1, X - 2) +
               .................... + 
               Sum(m, n - 1, X - m)

Why DP approach?
The above problem exhibits overlapping subproblems. See the below diagram. Also, see this recursive implementation. Let there be 3 dice, each with 6 faces and we need to find the number of ways to get sum 8:

diceThrow2

Sum(6, 3, 8) = Sum(6, 2, 7) + Sum(6, 2, 6) + Sum(6, 2, 5) + 
               Sum(6, 2, 4) + Sum(6, 2, 3) + Sum(6, 2, 2)

To evaluate Sum(6, 3, 8), we need to evaluate Sum(6, 2, 7) which can 
recursively written as following:
Sum(6, 2, 7) = Sum(6, 1, 6) + Sum(6, 1, 5) + Sum(6, 1, 4) + 
               Sum(6, 1, 3) + Sum(6, 1, 2) + Sum(6, 1, 1)

We also need to evaluate Sum(6, 2, 6) which can recursively written
as following:
Sum(6, 2, 6) = Sum(6, 1, 5) + Sum(6, 1, 4) + Sum(6, 1, 3) +
               Sum(6, 1, 2) + Sum(6, 1, 1)
..............................................
..............................................
Sum(6, 2, 2) = Sum(6, 1, 1)

Please take a closer look at the above recursion. The sub-problems in RED are solved first time and sub-problems in BLUE are solved again (exhibit overlapping sub-problems). Hence, storing the results of the solved sub-problems saves time.


For DP:

Time Complexity: O(m * n * x) where m is number of faces, n is number of dice and x is given sum.

We can add following two conditions at the beginning of findWays() to improve performance of program for extreme cases (x is too high or x is too low)

// When x is so high that sum can not go beyond x even when we
// get maximum value in every dice throw.
if (m*n <= x)
     return (m*n == x);
 
// When x is too low
if (n >= x)
     return (n == x);

With above conditions added, time complexity becomes O(1) when x >= m*n or when x <= n.

文中的骰子不一定就是6面的,可以是任意面。


package DP;

public class DiceThrow {

	public static void main(String[] args) {
		System.out.println(findWaysRec(4, 2, 1));
		System.out.println(findWaysRec(2, 2, 3));
		System.out.println(findWaysRec(6, 3, 8));
		System.out.println(findWaysRec(4, 2, 5));
		System.out.println(findWaysRec(4, 3, 5));
		System.out.println(findWaysDP(4, 2, 1));
		System.out.println(findWaysDP(2, 2, 3));
		System.out.println(findWaysDP(6, 3, 8));
		System.out.println(findWaysDP(4, 2, 5));
		System.out.println(findWaysDP(4, 3, 5));
	}

	// 返回能使组合之和为sum的方法数
	// faces:一个dice的最大面值,所有面值为:[1...faces]
	// dices:dices的个数,每个dice都可以选择一个face
	public static int findWaysRec(int faces, int dices, int sum){
		if(sum < 1){		// 总和过小
			return 0;
		}
		if(dices == 1){	// 只有一个dice,判断总和和最大面值哪个大
			return sum<=faces ? 1 : 0;
		}
		
		int ways = 0;
		for(int i=1; i<=faces; i++){
			ways += findWaysRec(faces, dices-1, sum-i);
		}
		return ways;
	}
	
	// The main function that returns number of ways to get sum 
	// Time Complexity: O(m * n * x) where m is number of faces, n is number of dice and x is given sum.
	public static int findWaysDP(int faces, int dices, int sum){
		int[][] dp = new int[dices+1][sum+1];	//dp[dices][sum]
		
		for(int sum_=1; sum_<=sum; sum_++){	// 只有1个dice且sum大于
			if(sum_ <= faces){
				dp[1][sum_] = 1;
			}
		}
		
		for(int dices_=2; dices_<=dices; dices_++){		// dices
			for(int sum_=1; sum_<=sum; sum_++){			// sum
				for(int faces_=1; faces_<=faces; faces_++){
					if(sum_-faces_ >= 0){		// 防越界
						dp[dices_][sum_] += dp[dices_-1][sum_-faces_];
					}
				}
			}
		}
		
		return dp[dices][sum];
	}
}


http://www.geeksforgeeks.org/dice-throw-problem/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]中提到了将BCE Loss和Dice Loss进行组合的方法,可以在数据较为均衡的情况下有所改善。然而,在数据极度不均衡的情况下,交叉熵会在迭代几个Epoch之后远远小于Dice Loss,这个组合Loss会退化为Dice Loss。所以,组合Dice Loss和Focal Loss可能会更好地解决前景背景不平衡的问题。引用\[2\]中提到,Dice Loss训练更关注对前景区域的挖掘,即保证有较低的FN,但会存在损失饱和问题,而CE Loss是平等地计算每个像素点的损失。因此,单独使用Dice Loss往往并不能取得较好的结果,需要进行组合使用,比如Dice Loss+CE Loss或者Dice Loss+Focal Loss等。所以,组合Dice Loss和Focal Loss可以综合考虑前景背景不平衡和损失饱和问题,从而取得更好的结果。 #### 引用[.reference_title] - *1* [分割常用损失函数](https://blog.csdn.net/m0_45447650/article/details/125620794)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [分割网络损失函数总结!交叉熵,Focal loss,Dice,iou,TverskyLoss!](https://blog.csdn.net/jijiarenxiaoyudi/article/details/128360405)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值