C 子集和二维动态规划
我试图找到一组n个数的子集,它们的和为m。例如,如果我有集合C 子集和二维动态规划,c,algorithm,C,Algorithm,我试图找到一组n个数的子集,它们的和为m。例如,如果我有集合(10,20,30,40,40,50,80)和m=90,那么子集是(10,80),(20,30,40)和(40,50)。我有一些代码可以找到像这样的小案例,比如 M[i, j] = max(M[i − 1, j], M[i − 1, j − A[i]) 然后使用 if (M[n][m]!=0) { for ( i = n; i >= 1; i --) if (M[i - 1][j]!=M[i][j])
(10,20,30,40,40,50,80)
和m=90
,那么子集是(10,80)
,(20,30,40)
和(40,50)
。我有一些代码可以找到像这样的小案例,比如
M[i, j] = max(M[i − 1, j], M[i − 1, j − A[i])
然后使用
if (M[n][m]!=0)
{
for ( i = n; i >= 1; i --)
if (M[i - 1][j]!=M[i][j])
{
printf ("Use item %d = %d\n", i, A[i]);
j -= A[i];
}
}
但是当我尝试更大的测试用例时,它不会返回所有的子集。非常感谢您的帮助。/*首先,我们使用快速排序对M进行排序,例如,
/* first we sort M with a quicksort, for instance,
whose an efficient implementation can be easily found on the web. */
M = quicksort(M);
/* we don't consider elements greater than m
so we compute the index of the greatest element to consider */
int max = n - 1;
for (; max > 0 && M[max] > m; max--);
int total = 1 << (max + 1);
for (int i = 0; i < total; i++)
{
/* In this loop we'll go through all the possible subsets of M */
int sum = 0;
for (int k=0; k<n; k++)
{
if ((1 << k) & i)
{
s += M[k];
/* if s is greater than m no need to go further */
if (s > m)
{
break;
}
}
}
if (sum == m)
{
/* Here we have found a successful subset so
we can output it however we want.
It is composed of all the elements used
to build s in the loop above */
}
}
它的高效实现可以在web上轻松找到*/
M=快速排序(M);
我们不认为元素大于M。
所以我们计算最大元素的索引来考虑*/
int max=n-1;
对于(;max>0&&M[max]>M;max--);
int total=1/*例如,首先我们使用快速排序对M进行排序,
它的高效实现可以在web上轻松找到*/
M=快速排序(M);
我们不认为元素大于M。
所以我们计算最大元素的索引来考虑*/
int max=n-1;
对于(;max>0&&M[max]>M;max--);
int-total=1所有的正数值都允许修剪,这大大降低了复杂性(但我不知道平均有多少)。对于大型集合,您可能需要更精确的算法,但如下所示:
将(多)集合排序为一个数组,例如nums
;例如,nums={10,20,30,40,40,50,80}
创建一个累积总和数组,cum
;那就是cum={10,30,60,100,140,190,270}
Now(C-ish伪码)
void parts(目标、索引、集合){//假设我们只想打印集合
如果(目标==0){
打印装置;
返回;
}
while(index>=0&&nums[index]>target)--index;//跳过过大的数字
如果(index<0 | | cum[index]=0&&cum[index]>=target;--index){//当总和太小时,我们可以停止
添加nums[index]进行设置;
零件(目标-nums[索引],索引-1,集合);
从集合中删除nums[索引];
//如果不需要重复集,请跳过重复集,例如,
//(40,50)将创建两次而不跳过:
//而(index>0&&nums[index-1]==nums[index])——index;
}
}
所有的正数都允许修剪,这大大降低了复杂性(但我不知道平均有多少)。对于大型集合,您可能需要更精确的算法,但如下所示:
将(多)集合排序为一个数组,例如nums
;例如,nums={10,20,30,40,40,50,80}
创建一个累积总和数组,cum
;那就是cum={10,30,60,100,140,190,270}
Now(C-ish伪码)
void parts(目标、索引、集合){//假设我们只想打印集合
如果(目标==0){
打印装置;
返回;
}
while(index>=0&&nums[index]>target)--index;//跳过过大的数字
如果(index<0 | | cum[index]=0&&cum[index]>=target;--index){//当总和太小时,我们可以停止
添加nums[index]进行设置;
零件(目标-nums[索引],索引-1,集合);
从集合中删除nums[索引];
//如果不需要重复集,请跳过重复集,例如,
//(40,50)将创建两次而不跳过:
//而(index>0&&nums[index-1]==nums[index])——index;
}
}
如果您不向我们展示您使用的代码,我们该如何帮助您?请不要显示项目中的所有代码,只显示相关的位。第一:这些数字都是正数(或者至少是非负数)?第二,你的例子包含40个两次,是打字错误还是允许多个元素?所有元素都是正数,允许多个元素。如果你不向我们展示你正在使用的代码,我们应该如何帮助你?请不要显示项目中的所有代码,只显示相关的位。第一:这些数字都是正数(或者至少是非负数)?第二,您的示例包含40个两次,是一个输入错误还是允许多个元素?所有元素都是正数,允许多个元素。如果我们循环遍历所有可能的子集,那么它就不是动态规划,正确吗?您可以编写一个更具动态性的解决方案:对于集合中的每个元素,您有两个选项W:它是否在成功的子集中。围绕这个想法,你可以建立一个递归的方法来考虑每一个新的元素,但是在最后,它仍然会遍历2个可能的子集,因为你想要所有和的相等的子集。m@PierrOz它通常不会遍历所有元素,因为您可以进行修剪(如果元素为非负)。在这个例子中,你不需要考虑任何包含80和50的子集(修剪2 ^(n-2)子集)等等。哦上帝,<代码> POW(2,N)< /代码>?为什么人们这么做?“我不明白为什么我们不考虑这个例子中的80和50?子集{10,80}和{50,40}符合条件。如果我们循环遍历所有可能的子集,那么它将不是动态规划,对吗?您可以编写一个更动态的解决方案:对于集合的每个元素,您有两个选项W:它是否在成功的子集中。围绕这个想法,你可以建立一个递归的方法来考虑每一个新的元素,但是在最后,它仍然会遍历2个可能的子集,因为你想要所有和的相等的子集。m@PierrOz它通常不会遍历所有元素,因为您可以进行修剪(如果元素为非负)。在这个例子中,你不需要考虑任何包含80和50的子集(修剪2 ^(n-2)子集)等等。哦上帝,<代码> POW(2,N)< /代码>?“人们为什么这样做?”丹尼尔菲什说
void parts(target, index, set){ // assuming we only want to print the sets out
if (target == 0){
print out set;
return;
}
while(index >= 0 && nums[index] > target) --index; // skip too large numbers
if (index < 0 || cum[index] < target) return; // done, all numbers too large or total too small
for(; index >= 0 && cum[index] >= target; --index){ // we can stop when the total sum is too small
add nums[index] to set;
parts(target - nums[index], index-1, set);
remove nums[index] from set;
// if no duplicate sets are desired, skip duplicates, for the example,
// (40,50) would be created twice without skipping:
// while(index > 0 && nums[index-1] == nums[index]) --index;
}
}