Description:
描述:
In this article, we are going to see a dynamic programing problem which can be featured in any interview rounds.
在本文中,我們將看到一個動態的編程問題,該問題可以在任何采訪回合中體現。
Problem statement:
問題陳述:
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.
給定n個骰子,每個骰子有m個面(從1到m編號),請找到獲得和X的方法數量。 X是拋出所有骰子時每個面上的值之和。
Input:
n=3
m=3
X=6
Output:
Total number of ways are: 7
Explanation:
說明:
Total number of dices: 3 say x1,x2,x3
Number of faces on each dice: 3 (1 to 3)
Total sum to be achieved: 6
We will write as xi(j)which means face value of dice xi is j
So sum 6 can be achieved in following ways:
6=x1(1)+x2(2)+x3(3)
6=x1(1)+x2(3)+x3(2)
6=x1(2)+x2(2)+x3(2)
6=x1(2)+x2(3)+x3(1)
6=x1(2)+x2(1)+x3(3)
6=x1(3)+x2(2)+x3(3)
6=x1(3)+x2(3)+x3(1)
This are total 7 ways to achieve the sum.
Solution Approach:
解決方法:
If it was only 1 dice, then if X<=m, the answer would be 1 else 0. Since there is only one way to achieve the sum if possible as there is only one dice.
如果只有1個骰子,那么如果X <= m ,答案將是1否則為0。由于只有一種骰子,因此只有一種方法可以實現總和。
Now when n, number of dice>1, then the problem becomes a recursive one
現在,當n ,骰子數> 1時,問題就變成了遞歸問題
We can think of the recursive function as?f(n,X) where n is number of dice and X is desired sum.
我們可以將遞歸函數視為f(n,X) ,其中n是骰子數, X是期望的和。
A single dice has m choices, which means the face can have values ranging 1 to m
So,
一個骰子有m個選擇,這意味著該面Kong的取值范圍為1到m
所以,
Recursively we can write,
我們可以遞歸地寫
That means summation of all choices for this particular dice to have face value 1 to minimum(X, m)
這意味著該特定骰子的所有選擇的總和的面值為1到最小值(X,m)
For our example case, n=3, m=3, X=6
對于我們的示例情況, n = 3,m = 3,X = 6
So, we need to find f(3,6)
因此,我們需要找到f(3,6)
f(3,6)=f(2,5)+f(2,4)+f(2,3)
f(2,5), f(2,4), f(2,3) all are sub problems themselves which are needed to be solved further. This would generate a recursion tree.
f(2,5),f(2,4),f(2,3)本身都是子問題,需要進一步解決。 這將生成一個遞歸樹。
Of course, we have base cases for single dice which is f(1,i)=1 for i=1 to m
當然,我們有單個骰子的基本情況, 對于i = 1到m,f(1,i)= 1
But this recursion will generate many overlapping sub problems, hence, we need to convert it to dynamic programing.
但是這種遞歸將產生許多重疊的子問題,因此,我們需要將其轉換為動態編程。
1) Declare dp[n+1][x+1] similar to f(n,x). Initialize it to 0.
2) Implement the base case f(1,i)
for i=1 to i minimum(m ,x)
dp[1][i]=1;
3) Fill the other values as per recursion relation
for i=2 to n //iterate for number of dices
for j=1 to x //iterate for sums
for k=1 to minimum(m ,j)
//iterate for face values up to minimum(m,j),j be the subsum
dp[i][j]+=dp[i-1][j-k];
end for
end for
end for
4) The answer is dp[n][x]
C++ Implementation:
C ++實現:
#include <bits/stdc++.h>
using namespace std;
long long int dicethrow(int m, int n, int x) {
if (m * n < x)
return 0;
long long dp[n + 1][x + 1];
memset(dp, 0, sizeof(dp));
//base case
for (int i = 1; i <= m && i <= x; i++)
dp[1][i] = 1;
for (int i = 2; i <= n; i++) { //iterate for number of dices
for (int j = 1; j <= x; j++) { //iterate for sums
//iterate for face values up to minimum(m,j),j be the subsum
for (int k = 1; k <= m & k < j; k++) {
dp[i][j] += dp[i - 1][j - k];
}
}
}
return dp[n][x];
}
int main() {
int n, m, x;
cout << "Enter number of dices, n:\n";
cin >> n;
cout << "Enter number of faces on a dice, m:\n";
cin >> m;
cout << "Enter sum, X:\n";
cin >> x;
cout << "Number of ways to achieve sum: " << dicethrow(m, n, x) << endl;
return 0;
}
Output
輸出量
RUN 1:
Enter number of dices, n:
3
Enter number of faces on a dice, m:
3
Enter sum, X:
6
Number of ways to achieve sum: 7
RUN 2:
Enter number of dices, n:
3
Enter number of faces on a dice, m:
3
Enter sum, X:
12
Number of ways to achieve sum: 0
In the second output there is no way to acquire the sum which can be verified as m*n<X. It's better practise to keep such base case to optimize your code :)
在第二個輸出中,無法獲取可以驗證為m * n <X的和 。 最好保留此類基本情況以優化代碼:)
翻譯自: https://www.includehelp.com/icp/dice-throw.aspx