找到2个相等的总和子序列,且总和最大?
我已删除该问题的所有故事情节。
Q.
给您N个数字。您必须找到2个相等和的子序列,且最大和。您不一定需要使用所有数字。
51 2 3 4 1
Sub-sequence 1 : 2 3 // sum = 5
Sub-sequence 2 : 4 1 // sum = 5
Possible Sub-sequences with equal sum are
{1,2} {3} // sum = 3
{1,3} {4} // sum = 4
{2,3} {4,1} // sum = 5
Out of which 5 is the maximum sum.
61 2 4 5 9 1
Sub-sequence 1 : 2 4 5 // sum = 11
Sub-sequence 2 : 1 9 1 // sum = 11
The maximum sum you can get is 11
5 <= N <= 501<= number <=1000
sum of all numbers is <= 1000
Important: Only <iostream> can be used. No STLs.
N numbers are unsorted.
If array is not possible to split, print 0.
Number of function stacks is limited. ie your recursive/memoization solution won't work.
我尝试了类似以下的递归方法:
#include <iostream>using namespace std;
bool visited[51][1001][1001];
int arr[51];
int max_height=0;
int max_height_idx=0;
int N;
void recurse( int idx, int sum_left, int sum_right){
if(sum_left == sum_right){
if(sum_left > max_height){
max_height = sum_left;
max_height_idx = idx;
}
}
if(idx>N-1)return ;
if(visited[idx][sum_left][sum_right]) return ;
recurse( idx+1, sum_left+arr[idx], sum_right);
recurse( idx+1, sum_left , sum_right+arr[idx]);
recurse( idx+1, sum_left , sum_right);
visited[idx][sum_left][sum_right]=true;
/*
We could reduce the function calls, by check the visited condition before calling the function.
This could reduce stack allocations for function calls. For simplicity I have not checking those conditions before function calls.
Anyways, this recursive solution would get time out. No matter how you optimize it.
Btw, there are T testcases. For simplicity, removed that constraint.
*/
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cin>>N;
for(int i=0; i<N; i++)
cin>>arr[i];
recurse(0,0,0);
cout<< max_height <<"\n";
}
NOTE:
通过测试用例。但是超时。
I also tried, taking advantage of constraints.Every number has 3 possible choice:
1. Be in sub-sequence 1
2. Be in sub-sequence 2
3. Be in neither of these sub-sequences
So
1. Be in sub-sequence 1 -> sum + 1*number
2. Be in sub-sequence 2 -> sum + -1*number
3. None -> sum
Maximum sum is in range -1000 to 1000.
So dp[51][2002] could be used to save the maximum positive sum achieved so far (ie till idx).
#include <iostream>using namespace std;
int arr[51];
int N;
int dp[51][2002];
int max3(int a, int b, int c){
return max(a,max(b,c));
}
int max4(int a, int b, int c, int d){
return max(max(a,b),max(c,d));
}
int recurse( int idx, int sum){
if(sum==0){
// should i perform anything here?
}
if(idx>N-1){
return 0;
}
if( dp[idx][sum+1000] ){
return dp[idx][sum+1000];
}
return dp[idx][sum+1000] = max3 (
arr[idx] + recurse( idx+1, sum + arr[idx]),
0 + recurse( idx+1, sum - arr[idx]),
0 + recurse( idx+1, sum )
) ;
/*
This gives me a wrong output.
4
1 3 5 4
*/
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cin>>N;
for(int i=0; i<N; i++)
cin>>arr[i];
cout<< recurse(0,0) <<"\n";
}
上面的代码给了我错误的答案。请帮助我解决/更正此备注。
同样也可以采用迭代方法。
回答:
第二种方法的想法是正确的,基本上可以简化背包问题。但是,您的代码似乎缺乏
:该recurse
函数应该做什么。
这里是我的建议:int recurse(int idx, int
sum)在岗位分配要素idx..n-1
分为三个多集A
,B
,C
使得sum+sum(A)-sum(B)=0
返回最大可能sum(A)
,-inf
否则(这里-inf
是一些硬编码的常量,它作为一个没有答案的“标记”;也有它的一些限制,我建议-inf
== -1000)。
现在,您将使用该合同编写一个递归回溯,然后添加备忘录。瞧-您有一个动态的编程解决方案。
在递归回溯中,我们有两种不同的情况:
- 没有更多要分配的元素,也没有做出选择的选择
idx == n
。在这种情况下,我们应该检查条件是否成立(sum + sum(A) - sum(B) == 0
,即sum == 0
)并返回答案。如果为sum == 0
,则答案为0。但是,如果为sum != 0
,则没有答案,我们应该返回永远不会被选择为答案的内容,除非对整个问题没有答案。当我们修改的返回值recurse
并且不希望有额外的if
s时,它不能简单地为零甚至是-1
; 它应该是一个经过修改的数字,仍然是“有史以来最糟糕的答案”。我们可以做的最大修改是将所有数字加到结果值上,因此我们应该选择小于或等于负的最大数字和(即-1000
),因为现有答案始终严格地是肯定的,而虚构的答案将始终是非肯定的。 - 有应分发到至少一个剩余元件
A
,B
或C
。做出选择,然后从三个选项中选择最佳答案。答案是递归计算的。
这是我的实现:
const int MAXN = 50;const int MAXSUM = 1000;
bool visited[MAXN + 1][2 * MAXSUM + 1]; // should be filled with false
int dp[MAXN + 1][2 * MAXSUM + 1]; // initial values do not matter
int recurse(int idx, int sum){
// Memoization.
if (visited[idx][sum + MAXSUM]) {
return dp[idx][sum + MAXSUM];
}
// Mark the current state as visited in the beginning,
// it's ok to do before actually computing it as we're
// not expect to visit it while computing.
visited[idx][sum + MAXSUM] = true;
int &answer = dp[idx][sum + MAXSUM];
// Backtracking search follows.
answer = -MAXSUM; // "Answer does not exist" marker.
if (idx == N) {
// No more choices to make.
if (sum == 0) {
answer = 0; // Answer exists.
} else {
// Do nothing, there is no answer.
}
} else {
// Option 1. Current elemnt goes to A.
answer = max(answer, arr[idx] + recurse(idx + 1, sum + arr[idx]));
// Option 2. Current element goes to B.
answer = max(answer, recurse(idx + 1, sum - arr[idx]));
// Option 3. Current element goes to C.
answer = max(answer, recurse(idx + 1, sum));
}
return answer;
}
以上是 找到2个相等的总和子序列,且总和最大? 的全部内容, 来源链接: utcz.com/qa/400916.html