思路:

  1. 分为n次掷出,但是为了避免重复,要求下一次掷出结果必须大于等于上一次掷出结果

  2. 上一次掷完后必然会对下一次能掷出的结果产生影响

如图:

wKioL1bzvZWRnXvLAABKPjSA3Sw051.png

4个骰子掷出20点

第一个骰子应该是掷出结果最小的骰子

第一个骰子取值的约束是

min:后面的骰子全是6,第一个骰子也能取1,所以不能小于2,

max:如果第一个是6,后面都得是6,显然不满足20

第二个骰子

第一种2情况取值的约束

min:必须大于第一个骰子的点数,必须大于18-(2*6)

max:不能大于6

不再详细解释

代码如下:

public static AtomicInteger count = new AtomicInteger(0);
	public static void main(String[] args) {
		List<int[]> result = dicing(new int[5],6, 5, 23);
		result.stream().forEach((l) -> System.out.println(Arrays.toString(l)));
		System.out.println(count.get());
	}

	public static List<int[]> dicing(int[] arr,int lastValue,int remainingDice, int remainingPoint) {
		List<int[]> result = new ArrayList<>();
		if (remainingDice == 1) {
			if (lastValue >= remainingPoint) {
				int[] temp = Arrays.copyOf(arr, arr.length);
				temp[arr.length-remainingDice] = remainingPoint;
				result.add(temp);
			}			
		} else {
			count.getAndIncrement();
			int max = findMin(lastValue, remainingPoint - remainingDice + 1, 6);
			int min = findMax(remainingPoint / remainingDice, 1);
			for(int i = max;i>=min;i--){
				int[] temp = Arrays.copyOf(arr, arr.length);
				temp[arr.length-remainingDice] = i;
				result.addAll(dicing(temp,i, remainingDice-1, remainingPoint-i));
			}		
		}
		return result;
	}

	public static int findMin(int a, int b, int c) {
		int min = a;
		if (min > b) {
			min = b;
		}
		if (min > b) {
			min = c;
		}
		return min;
	}

	public static int findMax(int a, int b) {
		int max = a;
		if (max < b) {
			max = b;
		}
		return max;
	}

4个骰子20点,结果如下:

[6, 6, 6, 2]

[6, 6, 5, 3]

[6, 6, 4, 4]

[6, 5, 5, 4]

[5, 5, 5, 5]

7

5个骰子23点,结果如下:

[6, 6, 6, 4, 1]

[6, 6, 6, 3, 2]

[6, 6, 5, 5, 1]

[6, 6, 5, 4, 2]

[6, 6, 5, 3, 3]

[6, 6, 4, 4, 3]

[6, 5, 5, 5, 2]

[6, 5, 5, 4, 3]

[6, 5, 4, 4, 4]

[5, 5, 5, 5, 3]

[5, 5, 5, 4, 4]

20