我正在处理一些需要我解决以下算法问题的任务:
<小时/> - 你收集了物品(它们的重量):[w1,w2,...,wn]
所以这个不是“背包0/1”问题,因为我们只处理权重(我们只有一个参数用于项目)。因此,我假设它可能有一个解决方案(Knapsack是NP-complete)或某种算法可以得到近似正确的结果。
请不要向我推荐“贪心算法”,因为我认为应该有一种能够提供更好结果的算法。我认为它应该是一个使用“动态编程”的算法。
提前谢谢你:)
答案 0 :(得分:2)
在这个特定情况下,您可以通过最小化行李中的可用空间来获得最大收益,因此将权重视为值。这个问题通常被称为subset sum problem,是背包问题家族的一个特例。
DP关系如下所示
在每个步骤中,您尝试在之前的元素集中添加最大值(不超过行李容量)加上新元素
子集求和问题的C ++实现回答了问题“我可以完全根据这些元素填充包吗?”和驱动程序如下
Calendar selected_cal = Calendar.getInstance();
selected_cal.setTime(selected_date);
//For next day
Calendar nextDay = Calendar.getInstance();
nextDay.add(Calendar.DATE, 1);//Adding one day
nextDay.set(Calendar.HOUR_OF_DAY, 0);//Setting calendar for start hour of the day
nextDay.set(Calendar.MINUTE, 0);//Setting calendar for start minute of the day
nextDay.set(Calendar.SECOND, 0);//Setting calendar for start second of the day
//For previous days
Calendar previousDay = Calendar.getInstance();
previousDay.add(Calendar.DATE, -2);//Adding one day
previousDay.set(Calendar.HOUR_OF_DAY, 23);//Setting calendar for start hour of the day
previousDay.set(Calendar.MINUTE, 59);//Setting calendar for start minute of the day
previousDay.set(Calendar.SECOND, 59);//Setting calendar for start second of the day
if(selected_cal.getTimeInMillis()>=nextDay.getTimeInMillis()
|| selected_cal.getTimeInMillis()<previousDay.getTimeInMillis()){
//Show error
}else{
//Do what you want to do
}
复杂性为bool ssp(const vector<int>& v, const int& N) {
vector<vector<int>> m( v.size() + 1 /* 1-based */,
vector<int>(N + 1 /* 1-based */, 0) );
// The line above also took care of the initialization for base
// cases f(i,0) = 0 and f(0,b) = 0
for (int i = 1; i <= v.size(); ++i) { // For each subset of elements
for (int b = 1; b <= N; ++b) { // For each subcapacity
int opt1 = m[i - 1][b];
int opt2 = -1;
if (b - v[i - 1] >= 0) { // No caching to keep this readable
opt2 = m[i - 1][b - v[i - 1]] + v[i - 1];
if (opt2 > b)
opt2 = -1; // Not allowed
}
m[i][b] = max(opt1, opt2);
}
}
return (m[v.size()][N] == N);
}
int main() {
const vector<int> v = { 1, 3, 7, 4 };
const int N = 11;
cout << "Subset sum problem can be solved with the given input: "
<< boolalpha << ssp(v, N); // true
return 0;
}
,其中O(N⋅I)
是起始集中的元素数。这是假多项式的复杂性。
答案 1 :(得分:1)
所描述的问题实际上不是0-1-Knapsack problem,而是一个特殊情况,也称为最大子集和问题,它被描述为here。它是NP
- 完整,这意味着它不比0-1-Knapsack复杂化更容易。
话虽如此,它可以通过任何针对0-1-Knapsack问题的优化算法来解决,方法是将项目利润设置为等于其权重。总之,可以使用以下动态编程算法将其解决为最优性; s[i]
表示i
项和m
是整数值状态空间的大小,其中m[i,s]
表示使用项rage中的项可达到的最大值{ {1}}。
{0,...i}
正如原始问题中提到的那样,以下贪婪算法产生了2近似,这是针对背包问题的类似算法的修改。
for j from 0 to W do:
m[0, j] := 0
for i from 1 to n do:
for j from 0 to W do:
if s[i] > j then:
m[i, j] := m[i-1, j]
else:
m[i, j] := max(m[i-1, j], m[i-1, j-s[i]] + s[i])
答案 2 :(得分:0)
看起来像Spoj problem。而我的解决方案是:
#include <bits/stdc++.h>
using namespace std;
int TimTongLonNhatCoGioiHan(int*arr, int songuoichoi, int gioihan){
int hmm = (int)(songuoichoi*songuoichoi/2);
int map[hmm];
int dem = 0, i, j, ox = songuoichoi - 1, oy = 0, result = 0, sum;
for(i = ox; i > oy; --i){
for(j = oy; j < ox; ++j){
map[dem] = arr[i] + arr[j];
// tinh tong lon nhat cua 3 so
for(int k = 0; k < songuoichoi; ++k){
if(k == j || k == i)
continue;
sum = map[dem] + arr[k];
if(sum > result && sum <= gioihan)
result = sum;
}
dem++;
}
-- ox;
}
return result;
}
int main() {
int sophantu = 0, songuoichoi = 0, gioihan = 0;
cin>>sophantu;
while(sophantu-->0){
cin>>songuoichoi;
int i = 0;
int arrCanNang[songuoichoi];
for(; i<songuoichoi; ++i){
cin>>arrCanNang[i];
}
cin>>gioihan;
cout<<TimTongLonNhatCoGioiHan(arrCanNang, songuoichoi, gioihan)<<"\n";
}
return 0;
}
为简单起见,您可以创建矩阵[w1,w2,...,wn] x [w1,w2,...,wn],放入sum(Wi,Wj),foreach k并找到MAX sum( Wi,Wj)+ Wk。