Divide and Conquer from iterative - algorithm

Given an (1-based) array a with n elements and function f(i, j) (1 ≤ i, j ≤ n) as (i - j)2 + g(i, j)2. Function g is calculated by the following pseudo-code:
int g(int i, int j)
{
int sum = 0;
for (int k = min(i, j) + 1; k <= max(i, j); k = k + 1)
sum = sum + a[k];
return sum;
}
Find a value mini ≠ j f(i, j).
I have created a iterative brute force algorithm for this but the solution need to be coded in divide and conquer.
Brute force algo :
def g_fun(i,j):
sum=0
for k in xrange(min(i,j)+1,max(i,j)+1):
sum+=arr[k-1]
return sum
def f_fun(i,j):
s=g_fun(i,j)
return ((i-j)**2 + s**2)
n=input("n : ")
arr=map(int,raw_input("Array : ").split())
low=100000 #infinity
for i in xrange(1,n+1):
for j in xrange(1,n+1):
if i!=j:
temp=f_fun(i,j)
if temp < low:
low=temp
print low

Related

algorithm problem, cost of merging list of integers

Let L be a list of positive integers.
We are allowed to merge two elements of L if they have adjacent indices.
The cost of this operation is the sum of both elements.
For example: [1,2,3,4] -> [3,3,4] with a cost of 3.
We are looking for the minimum cost to merge L into one integer.
Is there a fast way of doing this? I came up with this naive recursive approach but that should
be O(n!).
I have noticed that it benefits a lot from memoization so I think there must be a way to avoid trying all possible permutations which will always result in O(n!).
def solveR(l):
if len(l) <= 2:
return sum(l)
else:
return sum(l) + min(solveR(l[1:]), solveR(l[:-1]),
solveR(l[len(l) // 2:]) + solveR(l[:len(l) // 2]))
This is much like this LeetCode problem, but with K = 2. The comments suggest that the time complexity is O(n^3). Here is some C++ code that implements the algorithm:
class Solution {
public:
int mergeStones(vector<int>& stones, int K) {
K = 2;
int N = stones.size();
if((N-1)%(K-1) > 0) return -1;
int sum[N+1] = {0};
for(int i = 1; i <= N; i++)
sum[i] = sum[i-1] + stones[i-1];
vector<vector<int>> dp(N, vector<int>(N,0));
for(int L=K; L<= N; L++)
for(int i=0, j=i+L-1; j<N; i++,j++) {
dp[i][j] = INT_MAX;
for (int k = i; k < j; k += (K-1))
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]);
if ((L-1)%(K-1) == 0)
dp[i][j] += (sum[j+1] - sum[i]); // add sum in [i,j]
}
return dp[0][N-1];
}
};

Number of ways to take k steps on a path of length N

We have a path of length N. At a time we can only take a unit step. How many ways we can take K steps while remaining inside the path. Initially we are at the 0th position.
example N =5
|---|---|---|---|---|
0 1 2 3 4 5
if k = 3 then we move like -
0->1->2->1
0->1->0->1
0->1->2->3
Can you please give some directions/links on how to approach this problem?
It's likely to be solvable using combinatorial methods rather than computational methods. But since you're asking on stackoverflow, I assume you want a computational solution.
There's a recurrence relation defining the number of paths ending at i:
P[N, 0, i] = 1 if i==0 otherwise 0
P[N, K, i] = 0 if i<0 or i>N
P[N, K, i] = P[N, K-1, i-1] + P[N, K-1, i+1]
We can iteratively compute the array of P[N, K, i] for i=0..N for a given K from the array P[N, K-1, i] for i=0..N.
Here's some Python code that does this. It uses a small trick of having an extra 0 at the end of the array so that r[-1] and r[N+1] are both zero.
def paths(N, K):
r = [1] + [0] * (N+1)
for _ in xrange(K):
r = [r[i-1]+r[i+1] for i in xrange(N+1)] + [0]
return sum(r)
print paths(5, 3)
This runs in O(NK) time.
A different (but related) solution is to let M be the (N+1) by (N+1) matrix consisting of 1's at positions (i+1,i) and (i,i+1) for i=0..N+1, and 0's elsewhere -- that is, 1's on the subdiagonal and superdiagonal. Then M^K (that is, M raised to the Kth power) contains at position (i, j) the number of paths from i to j in K steps. So sum(M^K[0,i] for i=0..N) is the total number of all paths starting at 0 of length K. This runs in O(N^3logK) time, so is better than the iterative method only if K is much larger than N.
Java implementation of first approach in accepted answer -
for (int i = 0; i <= K; i++) {
for (int j = 1; j <= N; j++) {
if (i > 0)
dp1[i][j] = (dp1[i - 1][j - 1] + dp1[i - 1][j + 1]) % 1000000007;
else
dp1[i][j] = 1;
}
}
System.out.println(dp1[K][N-1])
Complexity O(KN)
Java DP implementation, it computes answers for all starting positions and values 1-N and 1-K -
for (int i = 0; i <= K; i++) {
for (int j = 1; j <= N; j++) {
for (int k = 1; k <= j; k++) {
if (i > 0)
dp[k][j][i] =
(dp[k - 1][j][i - 1] + dp[k + 1][j][i - 1]) % 1000000007;
else
dp[k][j][i] = 1;
}
}
}
System.out.println(dp[1][5][3]);
O(KN^2)

Optimize: Divide an array into continuous subsequences of length no greater than k such that sum of maximum value of each subsequence is minimum

Optimize O(n^2) algorithm to O(n log n).
Problem Statement
Given array A of n positive integers. Divide the array into continuous subsequences of length no greater than k such that sum of maximum value of each subsequence is minimum. Here's an example.
If n = 8 and k = 5 and elements of the array are 1 4 1 3 4 7 2 2, best solution is 1 | 4 1 3 4 7 | 2 2. The sum would be max{1} + max{4, 1, 3, 4, 7} + max{2, 2} = 1 + 7 + 2 = 10.
O(n^2) solution
Let dp[i] be the minimum sum as in problem statement for subproblem array A[0] ... A[i]. dp[0] = A[0] and, for 0 < i < n (dp[-1] = 0),
// A, n, k, - defined
// dp - all initialized to INF
dp[0] = A[0];
for (auto i = 1; i < n; i++) {
auto max = -INF;
for (auto j = i; j >= 0 && j >= i-k+1; j--) {
if (A[j] > max)
max = A[j];
auto sum = max + (j > 0 ? dp[j-1] : 0);
if (sum < dp[i])
dp[i] = sum;
}
}
// answer: dp[n-1]
O(n log n) ?
The problem author claimed that it was possible to solve this in O(n log n) time, and there are some people who were able to pass the test cases. How can this be optimized?
NOTE: I'm gonna change slightly your dynamic programming relation, so that there is no special case if j = 0. Now dp[j] is the answer for the first j termsA[0], ..., A[j-1] and:
dp[i] = min(dp[j] + max(A[j], ..., A[i-1]), i-k <= j < i)
The answer of the problem is now dp[n].
Notice that if j < i and dp[j] >= dp[i], you won't need dp[j] in the following transitions, because max(A[j], ..., A[l]) >= max(A[i], ..., A[l]) (so it will be always better to cut at i instead of j.
Furthermore let C[j] = max(A[j+1], ..., A[l]) (where l is our current index in the dynamic programming step, ie. i in your C++ program).
Then you can keep in memory some set of indices x1 < ... < xm (the "interesting" indices for the transitions of your dynamic programming relation) such that: dp[x1] < ... < dp[xm] (1). Then automatically C[x1] >= ... >= C[xm] (2).
To store {x1, ..., xm}, we need some data structure that supports the following operations:
Pop back (when we move from i to i+1, we must say that i-k is now unreachable) or front (cf. insertion).
Push front x (when we have computed dp[i], we insert it while preserving (1), by deleting the corresponding elements).
Compute min(dp[xj] + C[xj], 1 <= j <= m).
Thus some queue to store x1, ..., xk together with a set to store all dp[xi] + C[xi] will be enough.
How do we both preserve (1) and update C when we insert an element i?
Before computing dp[i], we update C with A[i-1]. For that we find the smallest element xj in the set x s.t. C[xj] <= A[i-1]. Then (1) and (2) imply dp[j'] + C[j'] >= dp[j] + C[j] for all j' >= j, so we update C[xj] to A[i-1] and we delete x(j+1), ..., xm from the set (*).
When we insert dp[i], we just delete all elements s.t. dp[j] >= dp[i] by popping front.
When we remove i-k, it may be possible that some element destroyed in (*) is now becoming best. So if necessary we update C and insert the last element.
Complexity : O(n log n) (there could be at most 2n insertions in the set).
This code sums up the main ideas:
template<class T> void relaxmax(T& r, T v) { r = max(r, v); }
vector<int> dp(n + 1);
vector<int> C(n + 1, -INF);
vector<int> q(n + 1);
vector<int> ne(n + 1, -INF);
int qback = 0, qfront = 0;
auto cmp = [&](const int& x, const int& y) {
int vx = dp[x] + C[x], vy = dp[y] + C[y];
return vx != vy ? vx < vy : x < y;
};
set<int, decltype(cmp)> s(cmp);
dp[0] = 0;
s.insert(0);
q[qfront++] = 0;
for (int i = 1; i <= n; ++i) {
C[i] = A[i - 1];
auto it_last = lower_bound(q.begin() + qback, q.begin() + qfront, i, [=](const int& x, const int& y) {
return C[x] > C[y];
});
for (auto it = it_last; it != q.begin() + qfront; ++it) {
s.erase(*it);
C[*it] = A[i - 1];
ne[*it] = i;
if (it == it_last) s.insert(*it);
}
dp[i] = dp[*s.begin()] + C[*s.begin()];
while (qback < qfront && dp[q[qfront]] >= dp[i]) {
s.erase(q[qfront]);
qfront--;
}
q[qfront++] = i;
C[i] = -INF;
s.insert(i);
if (q[qback] == i - k) {
s.erase(i - k);
if (qback + 1 != qfront && ne[q[qback]] > q[qback + 1]) {
s.erase(q[qback + 1]);
relaxmax(C[q[qback + 1]], C[i - k]);
s.insert(q[qback + 1]);
}
qback++;
}
}
// answer: dp[n]
This time I stress-tested it against your algorithm: see here.
Please let me know if it's still unclear.

Variant of Subset-Sum

Given 3 positive integers n, k, and sum, find exactly k number of distinct elements a_i, where
a_i \in S, 1 <= i <= k, and a_i \neq a_j for i \neq j
and, S is the set
S = {1, 2, 3, ..., n}
such that
\sum_{i=1}^{k}{a_i} = sum
I don't want to apply brute force (checking all possible combinations) to solve the problem due to exponential complexity. Can someone give me a hint towards another approach in solving this problem? Also, how can we exploit the fact the set S is sorted?
Is it possible to have complexity of O(k) in this problem?
An idea how to exploit 1..n set properties:
Sum of k continuous members of natural row starting from a is
sum = k*(2*a + (k-1))/2
To get sum of such subsequence about needed s, we can solve
a >= s/k - k/2 + 1/2
or
a <= s/k - k/2 + 1/2
compare s and sum values and make corrections.
For example, having s=173, n=40 and k=5, we can find
a <= 173/5 - 5/2 + 1/2 = 32.6
for starting number 32 we have sequence 32,33,34,35,36 with sum = 170, and for correction by 3 we can just change 36 with 39, or 34,35,36 with 35,36,37 and so on.
Seems that using this approach we get O(1) complexity (of course, there might exist some subtleties that I did miss)
It's possible to modify the pseudo-polynomial algorithm for subset sum.
Prepare a matrix P with dimension k X sum, and initialize all elements to 0. The meaning of P[p, q] == 1 is that there is a subset of p numbers summing to q, and P[p, q] == 0 means that such a subset has not yet been found.
Now iterate over i = 1, ..., n. In each iteration:
If i ≤ sum, set P[1, i] = 1 (there is a subset of size 1 that achieves i).
For any entry P[p, q] == 1, you now know that P[p + 1, q + i] should now be 1 too. If (p + 1, q + i) is within the boundaries of the matrix, set P[p + 1, q + i] = 1.
Finally, check if P[k, sum] == 1.
The complexity, assuming that all integer math operations is constant, is Θ(n2 sum).
There is a O(1) (so to speak) solution. What follows is a formal enough (I hope) development of the idea by #MBo.
It is sufficient to assume that S is a set of all integers and find a minimal solution. Solution K is smaller than K' iff max(K) < max(K'). If max(K) <= n, then K is also a solution to the original problem; otherwise, the original problem has no solution.
So we disregard n and find K, a minimal solution. Let g = max(K) = ceil(sum/k + (k - 1)/2) and s = g + (g-1) + (g-2) + ... (g-k+1) and s' = (g-1) + (g-2) + ... + (g-k). That is, s' is s shifted down by 1. Note s' = s - k.
Obviously s >= sum and (because K is minimal) s' < sum.
If s == sum the solution is K and we're done. Otherwise consider the set K+ = {g, g-1, ..., g-k}. We know that \sum(K+ \setminus {g}) < sum and \sum(K+ \setminus {g-k}) > sum, therefore, there's a single element g_i of K+ such that \sum (K+ \setminus {g_i}) = sum. The solution isK+ \setminus {\sum(K+)-sum}.
The solution in the form of 4 integers a, b, c, d where the actual set is understood to be [a..b] \setunion [c..d] can be computed in O(1).
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
unsigned long int arithmeticSum(unsigned long int a, unsigned long int k, unsigned long int n, unsigned long int *A);
void printSubset(unsigned long int k, unsigned long int *A);
int main(void)
{
unsigned long int n, k, sum;
// scan the respective values of sum, n, and k
scanf("%lu %lu %lu", &sum, &n, &k);
// find the starting element using the formula for the sum of an A.P. having 'k' terms
// starting at 'a', common difference 'd' ( = 1 in this problem), having 'sum' = sum
// sum = [k/2][2*a + (k-1)*d]
unsigned long startElement = (long double)sum/k - (long double)k/2 + (long double)1/2;
// exit if the arithmetic progression formed at the startElement is not within the required bounds
if(startElement < 1 || startElement + k - 1 > n)
{
printf("-1\n");
return 0;
}
// we now work on the k-element set [startElement, startElement + k - 1]
// create an array to store the k elements
unsigned long int *A = malloc(k * sizeof(unsigned long int));
// calculate the sum of k elements in the arithmetic progression [a, a + 1, a + 2, ..., a + (k - 1)]
unsigned long int currentSum = arithmeticSum(startElement, k, n, A);
// if the currentSum is equal to the required sum, then print the array A, and we are done
if(currentSum == sum)
{
printSubset(k, A);
}
// we enter into this block only if currentSum < sum
// i.e. we need to add 'something' to the currentSum in order to make it equal to sum
// i.e. we need to remove an element from the k-element set [startElement, startElement + k - 1]
// and replace it with an element of higher magnitude
// i.e. we need to replace an element in the set [startElement, startElement + k - 1] and replace
// it with an element in the range [startElement + k, n]
else
{
long int j;
bool done;
// calculate the amount which we need to add to the currentSum
unsigned long int difference = sum - currentSum;
// starting from A[k-1] upto A[0] do the following...
for(j = k - 1, done = false; j >= 0; j--)
{
// check if adding the "difference" to A[j] results in a number in the range [startElement + k, n]
// if it does then replace A[j] with that element, and we are done
if(A[j] + difference <= n && A[j] + difference > A[k-1])
{
A[j] += difference;
printSubset(k, A);
done = true;
break;
}
}
// if no such A[j] is found then, exit with fail
if(done == false)
{
printf("-1\n");
}
}
return 0;
}
unsigned long int arithmeticSum(unsigned long int a, unsigned long int k, unsigned long int n, unsigned long int *A)
{
unsigned long int currentSum;
long int j;
// calculate the sum of the arithmetic progression and store the each member in the array A
for(j = 0, currentSum = 0; j < k; j++)
{
A[j] = a + j;
currentSum += A[j];
}
return currentSum;
}
void printSubset(unsigned long int k, unsigned long int *A)
{
long int j;
for(j = 0; j < k; j++)
{
printf("%lu ", A[j]);
}
printf("\n");
}

Efficiently evaluating a recursive function?

I came across with an interesting puzzle on my previous interview.
You need to implement a function which would fit the following conditions:
m, n - positive integer numbers > 0
F(m, n) = F(m-1, n-1) + F(m, n-1)
F(1, n) = 1
F(m, 1) = 1
Obviously you can write the recursive implementation:
int F(int m, int n)
{
if(m == 1) return 1;
if(n == 1) return 1;
return F(m-1, n-1) + F(m, n-1);
}
But for input data equals one billion it will run very long time because it will get 2^1000000000 iterations :)
Does anybody have any ideas how to optimize this solution?
function F(m, n)
v = 1
s = 1
k = 1
while k < m do
v = v * (n-k) / k
s = s + v
k = k + 1
end
return s
end

Resources