我必须使用动态编程解决一个经典的分区问题。我有一个正整数数组作为输入,其中n是整数的数量,s是这些整数的总和,我需要找到可以使用输入元素构造的两个集合之间的最小差异。我还需要输出一个名为“所有权”的布尔数组,其大小与输入数组相同,它提供了元素是否属于第一个或第二个最优集的信息。例如,如果所有权数组中的第 i 个值为 true ,则输入数组的第 i 个元素属于第一个集合。
我的程序使用自下而上的方法找到最小的差异。该任务要求程序的内存复杂度为θ ( s ),因此我不使用经典方法中大小为 n*s 的二维数组,而是仅使用该数组的两行。在第一行中,我保留了之前处理过的行,因此我可以根据之前的解决方案填充第二行。
问题是,通过这种内存优化,我不确定应该如何填充所有权数组。
我知道可以使用 n*s 数组中的回溯来检索集合元素。但是,由于任务限制,我无法使用该方法,也不知道如何有效地构建所有权表。
有没有一种方法可以有效地找到哪些元素属于这两个最优集合中的哪一个,并且在自下而上的方法中 受到内存复杂度θ ( s ) 和时间复杂度O (n*s) 的约束?
我当前的 C# 代码:
public int SetsMinimum(int[] tab, out bool[] ownership)
{
int n = tab.Length;
int sum = 0;
foreach (int v in tab) sum += v;
ownership = new bool[n];
bool[,] dp = new bool[2, sum + 1];
int min = sum;
dp[0, 0] = true;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= sum; j++)
{
dp[1,j] = dp[0,j];
if (j - tab[i - 1]>=0)
{
dp[1, j] = dp[0, j - tab[i - 1]];
}
}
for(int j=0;j<sum;j++)
{
if (dp[1, j])
{
int cMin = Math.Abs((sum - j) - j);
if (min>cMin)
{
min = cMin;
}
}
dp[0, j] = dp[1, j];
}
}
return min;
}