声明:
给定一个n个整数的集合,将集合分成两个大小为n/2的子集,使两个子集之和的差值尽可能小。若n为偶数,则两个子集的大小必须严格为n/2,若n为奇数,则一个子集的大小必须为(n-1)/2,另一个子集的大小必须为(n+1)/2。
例如,设给定集为
{3, 4, 5, -3, 100, 1, 89, 54, 23, 20}
{4, 100, 1, 23, 20}
{3, 5, -3, 89, 54}
{23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4}
输出子集应为
{45, -34, 12, 98, -1}
而且
{23, 0, -99, 4, 189, 4}
两个子集的元素和分别为120和121。
for (int i = 1; i <= N; ++i)
for (int j = sum; j >= 0; --j)
if (dp[j])
dp[j + W[i]] |= dp[j] << 1;
我觉得这句话说得很清楚。
// If (dp[i] << j) & 1 is 1, that means it is possible
// to select j out of the N people so that the sum of
// their weight is i.
从初始条件dp[0]=1<<0开始,意思是“可以选择0个人,使他们的权重之和为0”。
然后,对于dp中非零的每个条目(即if(dp[j])
部分),更新列表中当前人员的dp。
请注意,这个算法不会告诉您需要选择哪些数字才能得到这个和;信息丢失了。它只会告诉你最好的两个和是什么。尽管稍微修改算法并使用某种数据结构来保留这些信息并不难(例如dp中的每个条目都说“我可以从3个数字中求出这个和,这些数字是……”)。
哦,还有关于向后迭代的问题:这是为了防止我们对同一个数字进行两次计数。如果第一个条目是1,我们会说“I can make 0 from 0 numbers;now I can make 1 from 1 numbers”。紧接着,“我可以从1个数字变成1;现在我可以从2个数字变成2”。等等。
编辑:既然你问了,这里有一种方法(请注意,如果你输入非正数,它就会坏掉,我就让你来解决这个问题):
int N;
int W[100 + 5];
std::map<int, std::vector<int>> dp[450 * 100 + 5];
void solve()
{
int sum = accumulate(W + 1, W + N + 1, 0);
// If (dp[i][j]) contains a nonempty vector, that means it is possible
// to select j out of the N people so that the sum of
// their weight is i, with those people's indices being the values of said vector
dp[W[1]][1].push_back(1);
for (int i = 2; i <= N; ++i)
{
for (int j = sum; j >= 0; --j)
{
for (std::map<int, std::vector<int>>::iterator it = dp[j].begin(); it != dp[j].end(); ++it)
{
dp[j + W[i]][it->first+1] = it->second;
dp[j + W[i]][it->first+1].push_back(i);
}
}
}
std::vector<int> selected;
int minDiff = 450 * 100;
int teamOneWeight = 0, teamTwoWeight = 0;
for (int i = 0; i <= sum; ++i)
{
if (!dp[i].empty())
{
int diff = abs(i - (sum - i));
if (diff < minDiff)
{
minDiff = diff;
teamOneWeight = i;
teamTwoWeight = sum-i;
selected = dp[i].begin()->second;
}
}
}
cout << "Team 1, sum of " << teamOneWeight << ": ";
for (int i = 1; i <= N; ++i)
{
if (std::find(selected.begin(), selected.end(), i) != selected.end())
cout << W[i] << ' ';
}
cout << endl << "Team 1, sum of " << teamTwoWeight << ": ";
for (int i = 1; i <= N; ++i)
{
if (std::find(selected.begin(), selected.end(), i) == selected.end())
cout << W[i] << ' ';
}
cout << endl;
}
如何将整数数组划分为N个子集,使这些子集的和最小? 例如,数组由11个元素组成,我需要其中的6个子集。 子集:<code>{2,1,1,3},{4},}4,3},}3,2},1,2},{3}</code>最小和=7。 另一个答案是:最小和=7。 注意:在分区时,必须保持数字在原始集合中出现的顺序。
我想在到期日对一个Retrient对象集合进行分组,但我想为每个组创建一个新的RentalReport对象,其中键是预定义的值(枚举),并且组是该对象的属性。我通过根据每个条件拟合集合并为每个条件创建一个RentalReport对象来实现这一点,但我想知道是否可以使用Collectors类的groupingBy方法来实现这一点。 有没有可能在Java 8中按一组预定义的过滤器进行分组,这样我就可以
我尝试使用Java8Lambda表达式和流来解析一些日志。我有一个巨大的日志文件,运行了一次又一次。我想把它分成不同的集合,每次运行一个集合。我不知道日志在advanced中运行了多少次。为了锻炼我非常虚弱的lambda肌肉,我想在列表中一次完成。 这是我目前的实现: 这里基本上类似于TomekRekawek的解决方案,但首先是未知的分区大小。
现有两个名为getDetails(…)的方法 。一个需要至少一个必需参数,另一个需要一个集合(不验证集合的内容/大小)。 问题是集合有时会作为空传递,并且根据我的业务案例,我总是期望至少传递一个值。因此,我需要将该方法设为私有,它接受集合。 我计划将下面的方法作用域设置为private,这样调用者就不会使用零属性调用此方法。 调用方方法之一是将集合对象传递给下面的getDetails, id.ge
我一直陷在这个问题中,找不到有效的解决办法。 我有N(高达1000万)说最大100个元素的数组。这些数组包含1-10000的数字。 现在我的问题是将这些数组划分为K个组,这样我就可以最小化所有数组中的重复项,即一个数组包含1,4,10,100,另一个数组包含1100。我希望他们进入同一组,因为这样可以最大限度地减少口是心非。我的问题的两个限制条件如下- > 组中向量的数量应均匀分布。 根据大小以递
问题内容: 我对Apache Spark和Python比较陌生,想知道像我将要描述的东西是否可行? 我有一个格式为[m 1,m 2,m 3,m 4,m 5,m 6, … m n ]的RDD(运行rdd.collect()时会得到这个)。我想知道是否有可能将此RDD转换为[[m 1,m 2,m 3),(m 4,m 5,m 6).....(m n-2, m n-1,m n)]。内部元组的大小应为k。如