algorithm - 选择球涂成红色的方法有多少?
问题描述
如何使用 DP 优化解决方案?
问题陈述:
我们有 3 个整数N、K、Q,其中,
N = 最初在袋子中的球数(从 1 到 N 编号,全部为白色),
K = 匝数,
Q = 我们在每回合从袋子中挑选的球数。
我们被要求返回一个大小为 (N + 1) 的数组,其中arr[i] 表示我们可以挑选球的方式的数量,这样在第 K回合结束时,恰好i数量的球应该是红色的。
我们应该采摘球的方式:
在每个回合中,我们必须从袋子中随机挑选出 Q 个球,并将白色的球涂成红色,红色的球保持原样,然后将它们放回袋子中。
这意味着在任何情况下(转),所有 N 个球(编号从 1 到 N)都存在于 bag 中。
约束:
1<=N<=100
1<=K<=100
1<=Q<=N
示例:
**INPUT**:
N = 3, K = 2, Q = 2,
Let the balls are numbered as 1, 2 and 3.
All possible ways to pick balls in K = 2 turns:
pick1 pick2
(1,2) (1,2) = 2 red balls
(1,3) (1,3) = 2 red balls
(3,2) (3,2) = 2 red balls
(1,2) (1,3) = 3 red balls
(1,2) (2,3) = 3 red balls
(1,3) (1,2) = 3 red balls
(1,3) (2,3) = 3 red balls
(2,3) (1,3) = 3 red balls
(2,3) (1,2) = 3 red balls
so, we have
0 ways to paint exactly 0 ball red in K number of turns,
0 ways to paint exactly 1 ball red in K number of turns,
3 ways to paint exactly 2 balls red in K number of turns &
6 ways to paint exactly 3 balls in K = 2 number of turns.
**OUTPUT**:
arr[] = [0, 0, 3, 6]
解决方案: 我试图将这个问题作为一个组合(C(n,r))问题来解决。并递归解决如下:
// utility function to calculate C(n,r)
void calculate_CnR(vector<vector<long long> > &C){
for(int n = 0; n < C.size(); n++){
for(int r = 0; r < C[0].size(); r++){
if(n >= r){
if(n == r || r == 0) C[n][r] = 1;
else if(r == 1) C[n][r] = n;
else C[n][r] = (C[n - 1][r - 1] % (1000000007) + C[n - 1][r] % (1000000007)) % (1000000007);
}
}
}
}
// main method
// B = number of balls left to paint red
// r = number of red balls present in bag currently
// w = number of white balls present in bag currently
// K = number of turns left
// Q = number of balls need to pick at each turn
// C = to access C(n,r) value in O(1) time
long long num_ways(int B, int r, int w, int K, const int &Q, const vector<vector<long long> > &C){
// base case
if(K == 0){ //turns over
if(B > 0)
return 0;
else if(B == 0)
return 1;
}
// decide maximum number of white balls we can pick
long long max_ = min(B, Q);
long long ways = 0;
for(int white_picks = 0; white_picks <= max_; white_picks++){
int red_picks = Q - white_picks;
if(red_picks <= r && white_picks <= w){ // red/white_picks num_balls must be present in the bag to pick.
ways += (
((C[w][white_picks] * C[r][red_picks]) % 1000000007)
*
(num_ways(B - white_picks, r + white_picks, w - white_picks, K - 1, Q, C) % 1000000007)
) % (1000000007);
}
}
return ways;
}
int main(){
// C[n][r] represents nCr
vector<vector<long long> > C(101, vector<long long>(101, 0));
calculate_CnR(C);
int tests = (cin>>tests, tests);
while(tests--){
int N = (cin>>N, N); // num balls
int K = (cin>>K, K); // turns
int Q = (cin>>Q, Q); // num of balls picked at each turn
vector<long long> ways(N + 1, 0);
for(int i = 1; i <= N; i++){
ways[i] = num_ways(i, 0, N, K, Q, C) % (1000000000 + 7);
}
}
return 0;
}
使用此代码,即使输入N = 50、Q = 3、K = 6,这也会给出 TLE(超出时间限制错误)
所以我认为DP(动态编程)可以以某种方式为我们节省计算时间,但我很难弄清楚这里存在重复的子问题。
解决方案
应用记忆。
// main method
// B = number of balls left to paint red
// r = number of red balls present in bag currently
// w = number of white balls present in bag currently
// K = number of turns left
// Q = number of balls need to pick at each turn
// C = to access C(n,r) value in O(1) time
为此,我们可以忽略运行中恒定的参数。
- C 和 Q 是常数,所以我们可以忽略它们。
- B+r 是常数,所以我们可以忽略其中一个(我选择忽略 B)
- r+w 是常数,所以我们可以忽略其中一个(我选择忽略 w)。
所以你有一个 r,K 的空间。如果你跟踪在运行期间你已经解决了哪些配置,你应该能够获得多项式复杂度并超过时间限制。
另一种思考方式是,中间状态是有多少种方式可以转 K 轮并有 r 个红球。
推荐阅读
- javascript - Kendo 内联网格组合框 TypeError:无法使用“in”运算符在 null 中搜索“Id”
- php - 如何在 Laravel 7 导出中获取变量值?
- python - Python:如何自动更新数组中的引用元素?
- plot - 可以用 jsxgraph 制作波特图
- javascript - 更新 TinyMce 模板插件
- flutter - 如何使用 GetX 包获取 Flutter 中的当前语言环境?
- html - 如何将 h5 元素移动到 div 的左上角?
- javascript - 反应对象和数组
- css - 在 CSS 预处理器中使用属性作为变量?
- excel - 当我将变量函数“cells(i,3)”添加到“Filter”时,运行时错误 440 无法解析