- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我是动态编程的新手,还不了解它可以解决的大多数类型的问题。因此,我在保持solution的Jewelry topcoder problem方面面临问题。
有人至少可以给我一些有关代码在做什么的提示吗?
最重要的是,此问题是subset-sum problem的变体吗?因为这就是我正在研究的解决这个问题的方法。
这两个函数实际上算什么?为什么我们实际上使用两个DP表?
void cnk() {
nk[0][0]=1;
FOR(k,1,MAXN) {
nk[0][k]=0;
}
FOR(n,1,MAXN) {
nk[n][0]=1;
FOR(k,1,MAXN)
nk[n][k] = nk[n-1][k-1]+nk[n-1][k];
}
}
void calc(LL T[MAXN+1][MAX+1]) {
T[0][0] = 1;
FOR(x,1,MAX) T[0][x]=0;
FOR(ile,1,n) {
int a = v[ile-1];
FOR(x,0,MAX) {
T[ile][x] = T[ile-1][x];
if(x>=a) T[ile][x] +=T[ile-1][x-a];
}
}
}
FOR(u,1,c) {
int uu = u * v[done];
FOR(x,uu,MAX)
res += B[done][x-uu] * F[n-done-u][x] * nk[c][u];
}
done=p;
}
最佳答案
让我们首先考虑以下任务:
“给定一个N个小于K的N个正整数的向量V,求和的总和等于S的子集数”。
这可以在多项式时间内使用一些额外的内存通过动态编程来解决。
动态编程方法如下:
除了解决N和S的问题外,我们还将解决以下形式的所有问题:
“找到仅使用数字的前n≤N个来写和(s≤S)的方式的数目”。
这是动态编程解决方案的一个共同特征:您不仅可以解决原始问题,还可以解决整个相关问题系列。关键思想是可以从较容易设置的解决方案中有效地建立更困难的问题设置(即更高的n和s)的解决方案。
解决n = 0的问题是微不足道的(总和s = 0可以用一种方式表示-使用空集,而所有其他总和不能以任何方式表示)。
现在考虑我们已经解决了直到某个n的所有值的问题,并且我们在矩阵A中拥有了这些解决方案(即A [n] [s]是使用前n个元素写和s的方式的数目) 。
然后,我们可以使用以下公式找到n + 1的解:
A [n + 1] [s] = A [n] [s-V [n + 1]] + A [n] [s]。
确实,当我们使用前n + 1个数字写和时,我们可以包括V [n + 1](不包括第n + 1个项)。
这就是calc
函数的计算结果。 (cnk
函数使用Pascal规则计算二项式系数)
注意:通常,如果最后我们只想回答初始问题(即,对于N和S),则数组A
可以是一维的(长度为S)-这是因为无论何时尝试构造n + 1的解,我们只需要n的解,而不是较小的值。
这个问题(此答案中最初指出的那个问题)确实与subset sum problem(找到总和为零的元素子集)有关。
如果我们对所使用整数的绝对值有合理的限制(可以分配一个辅助数组来表示所有可能的和),则可以应用类似类型的动态规划方法。
在零和问题中,我们实际上对计数不感兴趣,因此A数组可以是布尔数组(指示总和是否可达到)。
另外,如果存在辅助阵列B,则可以使用该辅助阵列B来重建解决方案。
现在,重复将如下所示:
if (!A[s] && A[s - V[n+1]]) {
A[s] = true;
// the index of the last value used to reach sum _s_,
// allows going backwards to reproduce the entire solution
B[s] = n + 1;
}
calc
函数计算了两个矩阵。
[5, 6, 7, 11, 15]
。
[5, 6, 7]
子数组中选择项目(最小的3个项目),而Frank将从其余的
[11, 12]
子数组中选择项目(最大2个项目)。在这种情况下,两者都可以得到一个总和(s = 11)。每次两者都能获得总和时,我们需要乘以它们各自达到各自总和的方式数(例如,如果鲍勃可以以4种方式达到总和s,而弗兰克可以通过5种方式达到同一总和s ,则我们可以用该总和获得20 = 4 * 5个有效解,因为每个组合都是有效解)。
res = 0;
for (int i = 0; i < n; i++) {
for (int s = 0; s <= maxS; s++) {
res += B[i][s] * F[n-i][s]
}
}
[5, 6] - [7, 11, 15]
以及间隔
[5, 6, 7] - [11, 15]
,都将计算总和为11的相同解。
res = 0;
for (int i = 0; i < n; i++) {
for (int s = v[i]; s <= maxS; s++) {
res += B[i][s - v[i]] * F[n - 1 - i][s];
}
}
done
对应于上面的
i
和
uu = v[i]
)。
comb(c, u) * B[i][s - u * v[i]]
(1)
F[n - i - u][s]
(2)
comb(c, u) * B[i][s - u * v[i]] * F[n - i - u][s]
。
done
对应于上面的变量i,变量
x
对应于和s,索引
p
用于确定与v [done]值相同的
c
项,并且遍历<使用cc>是为了考虑Bob挑选的此类物品的所有可能数量。
关于algorithm - 需要帮助来了解Jewelry Topcoder解决方案的解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48059479/
我是一名优秀的程序员,十分优秀!