Related
I have removed all the storylines for this question.
Q. You are given N numbers. You have to find 2 equal sum sub-sequences, with maximum sum. You don't necessarily need to use all numbers.
Eg 1:-
5
1 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.
Eg 2:-
6
1 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
Constraints:
5 <= N <= 50
1<= 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.
Approach 1:
I tried a recursive approach something like the below:
#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: Passes test-cases. But time out.
Approach 2:
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).
CODE:
#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";
}
The above code gives me wrong answer. Kindly help me with solving/correcting this memoization.
Also open to iterative approach for the same.
Idea of your second approach is correct, it's basically a reduction to the knapsack problem. However, it looks like your code lacks clear contract: what the recurse function is supposed to do.
Here is my suggestion: int recurse(int idx, int sum) distributes elements on positions idx..n-1 into three multisets A, B, C such that sum+sum(A)-sum(B)=0 and returns maximal possible sum(A), -inf otherwise (here -inf is some hardcoded constant which serves as a "marker" of no answer; there are some restrictions on it, I suggest -inf == -1000).
Now you're to write a recursive backtracking using that contract and then add memoization. Voila—you've got a dynamic programming solution.
In recursive backtracking we have two distinct situations:
There are no more elements to distribute, no choices to make: idx == n. In that case, we should check that our condition holds (sum + sum(A) - sum(B) == 0, i.e. sum == 0) and return the answer. If sum == 0, then the answer is 0. However, if sum != 0, then there is no answer and we should return something which will never be chosen as the answer, unless there are no answer for the whole problem. As we modify returning value of recurse and do not want extra ifs, it cannot be simply zero or even -1; it should be a number which, when modified, still remains "the worst answer ever". The biggest modification we can make is to add all numbers to the resulting value, hence we should choose something less or equal to negative maximal sum of numbers (i.e. -1000), as existing answers are always strictly positive, and that fictive answer will always be non-positive.
There is at least one remaining element which should be distributed to either A, B or C. Make the choice and choose the best answer among three options. Answers are calculated recursively.
Here is my implementation:
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;
}
Here is a simple dynamic programming based solution for anyone interested, based on the idea suggested by Codeforces user lemelisk here. Complete post here. I haven't tested this code completely though.
#include <iostream>
using namespace std;
#define MAXN 20 // maximum length of array
#define MAXSUM 500 // maximum sum of all elements in array
#define DIFFSIZE (2*MAXSUM + 9) // possible size of differences array (-maxsum, maxsum) + some extra
int dp[MAXN][DIFFSIZE] = { 0 };
int visited[DIFFSIZE] = { 0 }; // visited[diff] == 1 if the difference 'diff' can be reached
int offset = MAXSUM + 1; // offset so that indices in dp table don't become negative
// 'diff' replaced by 'offset + diff' below everywhere
int max(int a, int b) {
return (a > b) ? a : b;
}
int max_3(int a, int b, int c) {
return max(a, max(b, c));
}
int main() {
int a[] = { 1, 2, 3, 4, 6, 7, 5};
int n = sizeof(a) / sizeof(a[0]);
int *arr = new int[n + 1];
int sum = 0;
for (int i = 1; i <= n; i++) {
arr[i] = a[i - 1]; // 'arr' same as 'a' but with 1-indexing for simplicity
sum += arr[i];
} // 'sum' holds sum of all elements of array
for (int i = 0; i < MAXN; i++) {
for (int j = 0; j < DIFFSIZE; j++)
dp[i][j] = INT_MIN;
}
/*
dp[i][j] signifies the maximum value X that can be reached till index 'i' in array such that diff between the two sets is 'j'
In other words, the highest sum subsets reached till index 'i' have the sums {X , X + diff}
See http://codeforces.com/blog/entry/54259 for details
*/
// 1 ... i : (X, X + diff) can be reached by 1 ... i-1 : (X - a[i], X + diff)
dp[0][offset] = 0; // subset sum is 0 for null set, difference = 0 between subsets
visited[offset] = 1; // initially zero diff reached
for (int i = 1; i <= n; i++) {
for (int diff = (-1)*sum; diff <= sum; diff++) {
if (visited[offset + diff + arr[i]] || visited[offset + diff - arr[i]] || visited[offset + diff]) {
// if difference 'diff' is reachable, then only update, else no need
dp[i][offset + diff] = max_3
(
dp[i - 1][offset + diff],
dp[i - 1][offset + diff + arr[i]] + arr[i],
dp[i - 1][offset + diff - arr[i]]
);
visited[offset + diff] = 1;
}
}
/*
dp[i][diff] = max {
dp[i - 1][diff] : not taking a[i] in either subset
dp[i - 1][diff + arr[i]] + arr[i] : putting arr[i] in first set, thus reducing difference to 'diff', increasing X to X + arr[i]
dp[i - 1][diff - arr[i]] : putting arr[i] in second set
initialization: dp[0][0] = 0
*/
// O(N*SUM) algorithm
}
cout << dp[n][offset] << "\n";
return 0;
}
Output:
14
State is not updated in Approach 1. Change the last line of recurse
visited[idx][sum_left][sum_right];
to
visited[idx][sum_left][sum_right] = 1;
Also memset the visited array to false before calling recurse from main.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I'm trying to write a Haskell program that calculates multiples. Basically, when given two integers a and b, I want to find how many integers 1 ≤ bi ≤ b are multiple of any integer 2 ≤ ai ≤ a. For example, if a = 3 and b = 30, I want to know how many integers in the range of 1-30 are a multiple of 2 or 3; there are 20 such integers: 2, 3, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 26, 27, 28, 30.
I have a C program that does this. I'm trying to get this translated into Haskell, but part of the difficulty is getting around the loops that I've used since Haskell doesn't use loops. I appreciate any and all help in translating this!
My C program for reference (sorry if formatting is off):
#define PRIME_RANGE 130
#define PRIME_CNT 32
#define UPPER_LIMIT (1000000000000000ull) //10^15
#define MAX_BASE_MULTIPLES_COUNT 25000000
typedef struct
{
char primeFactorFlag;
long long multiple;
}multipleInfo;
unsigned char primeFlag[PRIME_RANGE + 1];
int primes[PRIME_CNT];
int primeCnt = 0;
int maxPrimeStart[PRIME_CNT];
multipleInfo baseMultiples[MAX_BASE_MULTIPLES_COUNT];
multipleInfo mergedMultiples[MAX_BASE_MULTIPLES_COUNT];
int baseMultiplesCount, mergedMultiplesCount;
void findOddMultiples(int a, long long b, long long *count);
void generateBaseMultiples(void);
void mergeLists(multipleInfo listSource[], int countS, multipleInfo
listDest[], int *countD);
void sieve(void);
int main(void)
{
int i, j, a, n, startInd, endInd;
long long b, multiples;
//Generate primes
sieve();
primes[primeCnt] = PRIME_RANGE + 1;
generateBaseMultiples();
baseMultiples[baseMultiplesCount].multiple = UPPER_LIMIT + 1;
//Input and Output
scanf("%d", &n);
for(i = 1; i <= n; i++)
{
scanf("%d%lld", &a, &b);
//If b <= a, all are multiple except 1
if(b <= a)
printf("%lld\n",b-1);
else
{
//Add all even multiples
multiples = b / 2;
//Add all odd multiples
findOddMultiples(a, b, &multiples);-
printf("%lld\n", multiples);
}
}
return 0;
}
void findOddMultiples(int a, long long b, long long *count)
{
int i, k;
long long currentNum;
for(k = 1; k < primeCnt && primes[k] <= a; k++)
{
for(i = maxPrimeStart[k]; i < maxPrimeStart[k + 1] &&
baseMultiples[i].multiple <= b; i++)
{
currentNum = b/baseMultiples[i].multiple;
currentNum = (currentNum + 1) >> 1; // remove even multiples
if(baseMultiples[i].primeFactorFlag) //odd number of factors
(*count) += currentNum;
else
(*count) -= currentNum;
}
}
}
void addTheMultiple(long long value, int primeFactorFlag)
{
baseMultiples[baseMultiplesCount].multiple = value;
baseMultiples[baseMultiplesCount].primeFactorFlag = primeFactorFlag;
baseMultiplesCount++;
}
void generateBaseMultiples(void)
{
int i, j, t, prevCount;
long long curValue;
addTheMultiple(3, 1);
mergedMultiples[0] = baseMultiples[0];
mergedMultiplesCount = 1;
maxPrimeStart[1] = 0;
prevCount = mergedMultiplesCount;
for(i = 2; i < primeCnt; i++)
{
maxPrimeStart[i] = baseMultiplesCount;
addTheMultiple(primes[i], 1);
for(j = 0; j < prevCount; j++)
{
curValue = mergedMultiples[j].multiple * primes[i];
if(curValue > UPPER_LIMIT)
break;
addTheMultiple(curValue, 1 - mergedMultiples[j].primeFactorFlag);
}
if(i < primeCnt - 1)
mergeLists(&baseMultiples[prevCount], baseMultiplesCount - prevCount, mergedMultiples, &mergedMultiplesCount);
prevCount = mergedMultiplesCount;
}
maxPrimeStart[primeCnt] = baseMultiplesCount;
}
void mergeLists(multipleInfo listSource[], int countS, multipleInfo listDest[], int *countD)
{
int limit = countS + *countD;
int i1, i2, j, k;
//Copy one list in unused safe memory
for(j = limit - 1, k = *countD - 1; k >= 0; j--, k--)
listDest[j] = listDest[k];
//Merge the lists
for(i1 = 0, i2 = countS, k = 0; i1 < countS && i2 < limit; k++)
{
if(listSource[i1].multiple <= listDest[i2].multiple)
listDest[k] = listSource[i1++];
else
listDest[k] = listDest[i2++];
}
while(i1 < countS)
listDest[k++] = listSource[i1++];
while(i2 < limit)
listDest[k++] = listDest[i2++];
*countD = k;
}
void sieve(void)
{
int i, j, root = sqrt(PRIME_RANGE);
primes[primeCnt++] = 2;
for(i = 3; i <= PRIME_RANGE; i+= 2)
{
if(!primeFlag[i])
{
primes[primeCnt++] = i;
if(root >= i)
{
for(j = i * i; j <= PRIME_RANGE; j += i << 1)
primeFlag[j] = 1;
}
}
}
}
First, unless I'm grossly misunderstanding, the number of multiples you have there is wrong. The number of multiples of 2 between 1 and 30 is 15, and the number of multiples of 3 between 1 and 30 is 10, so there should be 25 numbers there.
EDIT: I did misunderstand; you want unique multiples.
To get unique multiples, you can use Data.Set, which has the invariant that the elements of the Set are unique and ordered ascendingly.
If you know you aren't going to exceed x = maxBound :: Int, you can get even better speedups using Data.IntSet. I've also included some test cases and annotated with comments what they run at on my machine.
{-# LANGUAGE BangPatterns #-}
{-# OPTIONS_GHC -O2 #-}
module Main (main) where
import System.CPUTime (getCPUTime)
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
main :: IO ()
main = do
test 3 30 -- 0.12 ms
test 131 132 -- 0.14 ms
test 500 300000 -- 117.63 ms
test :: Int -> Int -> IO ()
test !a !b = do
start <- getCPUTime
print (numMultiples a b)
end <- getCPUTime
print $ "Needed " ++ show ((fromIntegral (end - start)) / 10^9) ++ " ms.\n"
numMultiples :: Int -> Int -> Int
numMultiples !a !b = IntSet.size (foldMap go [2..a])
where
go :: Int -> IntSet
go !x = IntSet.fromAscList [x, x+x .. b]
I'm not really into understanding your C, so I implemented a solution afresh using the algorithm discussed here. The N in the linked algorithm is the product of the primes up to a in your problem description.
So first we'll need a list of primes. There's a standardish trick for getting a list of primes that is at once very idiomatic and relatively efficient:
primes :: [Integer]
primes = 2:filter isPrime [3..]
-- Doesn't work right for n<2, but we never call it there, so who cares?
isPrime :: Integer -> Bool
isPrime n = go primes n where
go (p:ps) n | p*p>n = True
| otherwise = n `rem` p /= 0 && go ps n
Next up: we want a way to iterate over the positive square-free divisors of N. This can be achieved by iterating over the subsets of the primes less than a. There's a standard idiomatic way to get a powerset, namely:
-- import Control.Monad
-- powerSet :: [a] -> [[a]]
-- powerSet = filterM (const [False, True])
That would be a fine component to use, but since at the end of the day we only care about the product of each powerset element and the value of the Mobius function of that product, we would end up duplicating a lot of multiplications and counting problems. It's cheaper to compute those two things directly while producing the powerset. So:
-- Given the prime factorization of a square-free number, produce a list of
-- its divisors d together with mu(d).
divisorsWithMu :: Num a => [a] -> [(a, a)]
divisorsWithMu [] = [(1, 1)]
divisorsWithMu (p:ps) = rec ++ [(p*d, -mu) | (d, mu) <- rec] where
rec = divisorsWithMu ps
With that in hand, we can just iterate and do a little arithmetic.
f :: Integer -> Integer -> Integer
f a b = b - sum
[ mu * (b `div` d)
| (d, mu) <- divisorsWithMu (takeWhile (<=a) primes)
]
And that's all the code. Crunched 137 lines of C down to 15 lines of Haskell -- not bad! Try it out in ghci:
> f 3 30
20
As an additional optimization, one could consider modifying divisorsWithMu to short-circuit when its divisor is bigger than b, as we know such terms will not contribute to the final sum. This makes a noticeable difference for large a, as without it there are exponentially many elements in the powerset. Here's how that modification looks:
-- Given an upper bound and the prime factorization of a square-free number,
-- produce a list of its divisors d that are no larger than the upper bound
-- together with mu(d).
divisorsWithMuUnder :: (Ord a, Num a) => a -> [a] -> [(a, a)]
divisorsWithMuUnder n [] = [(1, 1)]
divisorsWithMuUnder n (p:ps) = rec ++ [(p*d, -mu) | (d, mu) <- rec, p*d<=n]
where rec = divisorsWithMuUnder n ps
f' :: Integer -> Integer -> Integer
f' a b = b - sum
[ mu * (b `div` d)
| (d, mu) <- divisorsWithMuUnder b (takeWhile (<=a) primes)
]
Not much more complicated; the only really interesting difference is that there's now a condition in the list comprehension. Here's an example of f' finishing quickly for inputs that would take infeasibly long with f:
> f' 100 100000
88169
With data-ordlist package mentioned by Daniel Wagner in the comments, it is just
f a b = length $ unionAll [ [p,p+p..b] | p <- takeWhile (<= a) primes]
That is all. Some timings, for non-compiled code run inside GHCi:
~> f 100 (10^5)
88169
(0.05 secs, 48855072 bytes)
~> f 131 (3*10^6)
2659571
(0.55 secs, 1493586480 bytes)
~> f 131 132
131
(0.00 secs, 0 bytes)
~> f 500 300000
274055
(0.11 secs, 192704760 bytes)
Compiling will surely make the memory consumption a non-issue, by converting the length to a counting loop.
You'll have to use recursion in place of loops.
In (most) procedural or object-orientated languages, you should hardly ever (never?) be using recursion. It is horribly inefficient, as a new stack frame must be created each time the recursive function is called.
However, in a functional language, like Haskell, the compiler is often able to optimize the recursion away into a loop, which makes it much faster then its procedural counterparts.
I've converted your sieve function into a set of recursive functions in C. I'll leave it to you to convert it into Haskell:
int main(void) {
//...
int root = sqrt(PRIME_RANGE);
primes[primeCnt++] = 2;
sieve(3, PRIME_RANGE, root);
//...
}
void sieve(int i, int end, int root) {
if(i > end) {
return;
}
if(!primeFlag[i]) {
primes[primeCnt++] = i;
if(root >= i) {
markMultiples(i * i, PRIME_RANGE, i);
}
}
i += 2;
sieve(i, end, root);
}
void markMultiples(int j, int end, int prime) {
if(j > end) {
return;
}
primeFlag[j] = 1;
j += i << 1;
markMultiples(j, end, prime);
}
The point of recursion is that the same function is called repeatedly, until a condition is met. The results of one recursive call are passed onto the next call, until the condition is met.
Also, why are you bit-fiddling instead of just multiplying or dividing by 2? Any half-decent compiler these days can convert most multiplications and divisions by 2 into a bit-shift.
I need help with this dynamic programming problem.
Given a positive integer k, find the maximum number of distinct positive integers that sum to k. For example, 6 = 1 + 2 + 3 so the answer would be 3, as opposed to 5 + 1 or 4 + 2 which would be 2.
The first thing I think of is that I have to find a subproblem. So to find the max sum for k, we need to find the max sum for the values less than k. So we have to iterate through the values 1 -> k and find the max sum for those values.
What confuses me is how to make a formula. We can define M(j) as the maximum number of distinct values that sum to j, but how do I actually write the formula for it?
Is my logic for what I have so far correct, and can someone explain how to work through this step by step?
No dynamic programming is need. Let's start with an example:
50 = 50
50 = 1 + 49
50 = 1 + 2 + 47 (three numbers)
50 = 1 + 2 + 3 + 44 (four numbers)
50 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 14 (nine numbers)
Nine numbers is as far as we can go. If we use ten numbers, the sum would be at least 1 + 2 + 3 + ... + 10 = 55, which is greater than 50 - thus it is impossible.
Indeed, if we use exactly n distinct positive integers, then the lowest number with such a sum is 1+2+...+n = n(n+1)/2. By solving the quadratic, we have that M(k) is approximately sqrt(2k).
Thus the algorithm is to take the number k, subtract 1, 2, 3, etc. until we can't anymore, then decrement by 1. Algorithm in C:
int M(int k) {
int i;
for (i = 1; ; i++) {
if (k < i) return i - 1;
else k -= i;
}
}
The other answers correctly deduce that the problem essentially is this summation:
However this can actually be simplified to
In code this looks like : floor(sqrt(2.0 * k + 1.0/4) - 1.0/2)
The disadvantage of this answer is that it requires you to deal with floating point numbers.
Brian M. Scott (https://math.stackexchange.com/users/12042/brian-m-scott), Given a positive integer, find the maximum distinct positive integers that can form its sum, URL (version: 2012-03-22): https://math.stackexchange.com/q/123128
The smallest number that can be represented as the sum of i distinct positive integers is 1 + 2 + 3 + ... + i = i(i+1)/2, otherwise known as the i'th triangular number, T[i].
Let i be such that T[i] is the largest triangular number less than or equal to your k.
Then we can represent k as the sum of i different positive integers:
1 + 2 + 3 + ... + (i-1) + (i + k - T[i])
Note that the last term is greater than or equal to i (and therefore different from the other integers), since k >= T[i].
Also, it's not possible to represent k as the sum of i+1 different positive integers, since the smallest number that's the sum of i+1 different positive integers is T[i+1] > k because of how we chose i.
So your question is equivalent to finding the largest i such that T[i] <= k.
That's solved by this:
i = floor((-1 + sqrt(1 + 8k)) / 2)
[derivation here: https://math.stackexchange.com/questions/1417579/largest-triangular-number-less-than-a-given-natural-number ]
You could also write a simple program to iterate through triangular numbers until you find the first larger than k:
def uniq_sum_count(k):
i = 1
while i * (i+1) <= k * 2:
i += 1
return i - 1
for k in xrange(20):
print k, uniq_sum_count(k)
I think you just check if 1 + ... + n > k. If so, print n-1.
Because if you find the smallest n as 1 + ... + n > k, then 1 + ... + (n-1) <= k. so add the extra value, say E, to (n-1), then 1 + ... + (n-1+E) = k.
Hence n-1 is the maximum.
Note that : 1 + ... + n = n(n+1) / 2
#include <stdio.h>
int main()
{
int k, n;
printf(">> ");
scanf("%d", &k);
for (n = 1; ; n++)
if (n * (n + 1) / 2 > k)
break;
printf("the maximum: %d\n", n-1);
}
Or you can make M(j).
int M(int j)
{
int n;
for (n = 1; ; n++)
if (n * (n + 1) / 2 > j)
return n-1; // return the maximum.
}
Well the problem might be solved without dynamic programming however i tried to look at it in dynamic programming way.
Tip: when you wanna solve a dynamic programming problem you should see when situation is "repetitive". Here, since from the viewpoint of the number k it does not matter if, for example, I subtract 1 first and then 3 or first 3 and then 1; I say that "let's subtract from it in ascending order".
Now, what is repeated? Ok, the idea is that I want to start with number k and subtract it from distinct elements until I get to zero. So, if I reach to a situation where the remaining number and the last distinct number that I have used are the same the situation is "repeated":
#include <stdio.h>
bool marked[][];
int memo[][];
int rec(int rem, int last_distinct){
if(marked[rem][last_distinct] == true) return memo[rem][last_distinct]; //don't compute it again
if(rem == 0) return 0; //success
if(rem > 0 && last > rem - 1) return -100000000000; //failure (minus infinity)
int ans = 0;
for(i = last_distinct + 1; i <= rem; i++){
int res = 1 + rec(rem - i, i); // I've just used one more distinct number
if(res > ans) ans = res;
}
marked[rem][last_distinct] = true;
memo[rem][last_distinct] = res;
return res;
}
int main(){
cout << rec(k, 0) << endl;
return 0;
}
The time complexity is O(k^3)
Though it isn't entirely clear what constraints there may be on how you arrive at your largest discrete series of numbers, but if you are able, passing a simple array to hold the discrete numbers, and keeping a running sum in your functions can simplify the process. For example, passing the array a long with your current j to the function and returning the number of elements that make up the sum within the array can be done with something like this:
int largest_discrete_sum (int *a, int j)
{
int n, sum = 0;
for (n = 1;; n++) {
a[n-1] = n, sum += n;
if (n * (n + 1) / 2 > j)
break;
}
a[sum - j - 1] = 0; /* zero the index holding excess */
return n;
}
Putting it together in a short test program would look like:
#include <stdio.h>
int largest_discrete_sum(int *a, int j);
int main (void) {
int i, idx = 0, v = 50;
int a[v];
idx = largest_discrete_sum (a, v);
printf ("\n largest_discrete_sum '%d'\n\n", v);
for (i = 0; i < idx; i++)
if (a[i])
printf (!i ? " %2d" : " +%2d", a[i]);
printf (" = %d\n\n", v);
return 0;
}
int largest_discrete_sum (int *a, int j)
{
int n, sum = 0;
for (n = 1;; n++) {
a[n-1] = n, sum += n;
if (n * (n + 1) / 2 > j)
break;
}
a[sum - j - 1] = 0; /* zero the index holding excess */
return n;
}
Example Use/Output
$ ./bin/largest_discrete_sum
largest_discrete_sum '50'
1 + 2 + 3 + 4 + 6 + 7 + 8 + 9 +10 = 50
I apologize if I missed a constraint on the discrete values selection somewhere, but approaching in this manner you are guaranteed to obtain the largest number of discrete values that will equal your sum. Let me know if you have any questions.
i have the recurrence relation of
and the initials condition is
a0 = a1 = 0
with these two, i have to find the bit strings of length 7 contain two consecutive 0 which i already solve.
example:
a2 = a2-1 + a2-2 + 22-2
= a1 + a0 + 20
= 0 + 0 + 1
= 1
and so on until a7.
the problem is how to convert these into c?
im not really good at c but i try it like this.
#include<stdio.h>
#include <math.h>
int main()
{
int a[7];
int total = 0;
printf("the initial condition is a0 = a1 = 0\n\n");
// a[0] = 0;
// a[1] = 0;
for (int i=2; i<=7; i++)
{
if(a[0] && a[1])
a[i] = 0;
else
total = (a[i-1]) + (a[i-2]) + (2 * pow((i-2),i));
printf("a%d = a(%d-1) + a(%d-2) + 2(%d-2)\n",i,i,i,i);
printf("a%d = %d\n\n",i,total);
}
}
the output are not the same as i calculate pls help :(
int func (int n)
{
if (n==0 || n==1)
return 0;
if (n==2)
return 1;
return func(n-1) + func(n-2) + pow(2,(n-2));
}
#include<stdio.h>
#include <math.h>
int main()
{
return func(7);
}
First of uncomment the lines which initialized the 2 first elements. Then at the for loop the only 2 lines need are:
a[i]=a[i-1]+a[i-2]+pow(2, i-2);
And then print a i
In the pow() function, pow(x,y) = x^y (which operates on doubles and returns double). The C code in your example is thus doing 2.0*(((double)i-2.0)^(double)i)... A simpler approach to 2^(i-2) (in integer math) is to use the bitwise shift operation:
total = a[i-1] + a[i-2] + (1 << i-2);
(Note: For ANSI C operator precedence consult an internet search engine of your choice.)
If your intention is to make the function capable of supporting floating point, then the pow() function would be appropriate... but the types of the variables would need to change accordingly.
For integer math, you may wish to consider using a long or long long type so that you have less risk of running out of headroom in the type.
I did this in c :
#include<stdio.h>
int main (void)
{
int n,i;
scanf("%d", &n);
for(i=2;i<=n;i=i+2)
{
if((i*i)%2==0 && (i*i)<= n)
printf("%d \n",(i*i));
}
return 0;
}
What would be a better/faster approach to tackle this problem?
Let me illustrate not only a fast solution, but also how to derive it. Start with a fast way of listing all squares and work from there (pseudocode):
max = n*n
i = 1
d = 3
while i < max:
print i
i += d
d += 2
So, starting from 4 and listing only even squares:
max = n*n
i = 4
d = 5
while i < max:
print i
i += d
d += 2
i += d
d += 2
Now we can shorten that mess on the end of the while loop:
max = n*n
i = 4
d = 5
while i < max:
print i
i += 2 + 2*d
d += 4
Note that we are constantly using 2*d, so it's better to just keep calculating that:
max = n*n
i = 4
d = 10
while i < max:
print i
i += 2 + d
d += 8
Now note that we are constantly adding 2 + d, so we can do better by incorporating this into d:
max = n*n
i = 4
d = 12
while i < max:
print i
i += d
d += 8
Blazing fast. It only takes two additions to calculate each square.
I like your solution. The only suggestions I would make would be:
Put the (i*i)<=n as the middle clause of your for loop, then it's checked earlier and you break out of the loop sooner.
You don't need to check and see if (i*i)%2==0, since 'i' is always positive and a positive squared is always positive.
With those two changes in mind you can get rid of the if statement in your for loop and just print.
Square of even is even. So, you really do not need to check it again. Following is the code, I would suggest:
for (i = 2; i*i <= n; i+=2)
printf ("%d\t", i*i);
The largest value for i in your loop should be the floor of the square root of n.
The reason is that the square of any i (integer) larger than this will be greater than n. So, if you make this change, you don't need to check that i*i <= n.
Also, as others have pointed out, there is no point in checking that i*i is even since the square of all even numbers is even.
And you are right in ignoring odd i since for any odd i, i*i is odd.
Your code with the aforementioned changes follows:
#include "stdio.h"
#include "math.h"
int main ()
{
int n,i;
scanf("%d", &n);
for( i = 2; i <= (int)floor(sqrt(n)); i = i+2 ) {
printf("%d \n",(i*i));
}
return 0;
}