好吧,看到数字不是整数而是实数,我能想到的最好的就是O(2^(n/2) log (2^(n/2))
.
乍一看可能看起来更糟,但请注意2^(n/2) == sqrt(2^n)
因此,为了实现这种复杂性,我们将使用中间相遇的技术:
- 拆分成两部分的大小
n/2
和n-n/2
- 使用蛮力生成所有子集(包括空子集)并将它们存储在数组中,我们称它们为 A 和 B
- 让我们对数组 B 进行排序
- 现在对于 A 中的每个元素
a
,如果B[-1] + a >=k
我们可以使用二进制搜索找到b
B 中满足的最小元素a + b >= k
- 在我们发现的所有这些
a + b
对中,选择最小的
OP现在稍微改变了它的整数问题,所以这里有动态解决方案:
好不多说,经典的背包。
对于 [1,n] 中的每个 i,我们有 2 个选项用于设置项目 i: 1. 包含在子集中,状态从(i, w)
变为(i+1, w + S[i])
2. 跳过它,状态从(i, w)
变为(i+1, w)
每次我们达到某个 >= k 的 w 时,我们都会更新答案
伪代码:
visited = Set() //some set/hashtable object to store visited states
S = [...]//set of integers from input
int ats = -1;
void solve(int i, int w) //theres atmost n*k different states so complexity is O(n*k)
{
if(w >= k)
{
if(ats==-1)ats=w;
else ats=min(ats,w);
return;
}
if(i>n)return;
if(visited.count(i,w))return; //we already visited this state, can skip
visited.insert(i,w)=1;
solve(i+1, w + S[i]); //take item
solve(i+1, w); //skip item
}
solve(1,0);
print(ats);