0/K knapsack. How to solve? - dynamic-programming

I am trying to learn Dynamic programming. I came across: https://youtu.be/U4O3SwDamA4?t=1407
I know basics of DP although they are not yet intuitive for me. Now, he talks about
0/1 knapsack
0/inf knap sack
and finally 0/k knapsack
While i tried to search 0/k knapsack, I am getting optimised solution (O(nS)) and not the solution that is extracted from 0/1 directly and have complexity of O(nKS). Anyone having nay resource to share or having a good grasp for the same is welcomed :) Thank you

I think the "naïve" solution the presenter is briefly mentioning has runtime complexity O(KS), given the way he defined K to be the sum of all the item limits. The idea is to convert it into a 0/1 problem by making ki copies of each item type.
Assume you've got k0 items of type 0, k1 items of type 1, and so on (so those are the limits to how many items you may take of each type). K is the total number of items (the sum of all the ki). Now, if you take this collection of items and start considering every item to be distinct from all the others, you have a 0/1 problem! The first item of type 0 is now item 0 in our new problem, the second item of type 0 is item 1 in our new problem, the last item of type 0 is item k0 - 1 in our new problem - and they all have weight w0 and value v0. The first item of type 1 is item k0 in our new problem, and so on. So we can now solve this as a 0/1 knapsack problem, but it's got K items instead of n; thus, the complexity is O(KS). However, if you define K to be the average of all the ki, or if every item has the same limit K, the complexity is indeed O(nKS).

Related

How do I get the Gross Value Added (GVA) of countries/industries from MRIO models?

I want to calculate the Gross Value Added for different countries and industries using multi-regional input-output (MRIO) tables. However, I struggle to find a good explanation of how this is done based on the data available. The definition of the GVA (Gross Value Added) is the output of a country/industry less the intermediate consumption, and it is related to the GDP by:
GVA = GDP + subsidies - taxes
So far, I have used the "extensions" or "satellite accounts" that provide the Value Added (VA) disaggregated across different flows, i.e. example from Exiobase in the picture. The VA is the sum of all 12 to my understanding. However, based on the definition of the GVA, I have subtracted 1-3 since these are taxes (so GVA = sum of line 4-12). To me, this seems like the correct approach, but I have not succeeded in finding an explanation that could confirm/disprove. I also become uncertain due to the naming of the extension, i.e. "value added" sounding like "gross value added". Does anyone know the correct way of doing this?
Finally, in MRIO x is termed "gross output" being the total output to final demand + intermediate consumption:
x = Ax + y (Ax = intermediate, y = demand)
or
x = (I-A)^-1 * y = L*y (L = Leontif inverse/requirement matrix)
Does this mean that I can also derive the GVAs from x by subtracting the intermediate consumption? In my mind, this will just leave me with "y", but there might be a another smart way?
Thanks in advance!
From what I understand, yes you can !
You have to differentiate Z = Ax summed along its rows or along its columns
x - rowSum(Z) is the GVA.
x - colSum(Z) is the total final demand.
Regarding Exiobase, I don't have a real answer.
I found that summing all lines of the VA (keeping lines 1-3), I get "quasi" the same results as subtracting the row sum of Z to x.
Which is stange...

Time complexity of my backtracking to find the optimal solution of the maximum sum non adjacent

I'm trying to do dynamic programming backtracking of maximum sum of non adjacent elements to construct the optimal solution to get the max sum.
Background:
Say if input list is [1,2,3,4,5]
The memoization should be [1,2,4,6,9]
And my maximum sum is 9, right?
My solution:
I find the first occurence of the max sum in memo (as we may not choose the last item) [this is O(N)]
Then I find the previous item chosen by using this formula:
max_sum -= a_list[index]
As in this example, 9 - 5 = 4, which 4 is on index 2, we can say that the previous item chosen is "3" which is also on the index 2 in the input list.
I find the first occurence of 4 which is on index 2 (I find the first occurrence because of the same concept in step 1 as we may have not chosen that item in some cases where there are multiple same amounts together) [Also O(N) but...]
The issue:
The third step of my solution is done in a while loop, let's say the non adjacent constraint is 1, the max amount we have to backtrack when the length of list is 5 is 3 times, approx N//2 times.
But the 3rd step, uses Python's index function to find the first occurence of the previous_sum [which is O(N)] memo.index(that_previous_sum)
So the total time complexity is about O(N//2 * N)
Which is O(N^2) !!!
Am I correct on the time complexity? Or am I wrong? Is there a more efficient way to backtrack the memoization list?
P.S. Sorry for the formatting if I done it wrong, thanks!
Solved:
I looped from behind checking if the item in front is same or not
If it's same, means it's not first occurrence. If not, it's first occurrence.
Tada! No Python's index function to find from the first index! We find it now from the back
So the total time complexity is about O(N//2 * N)
Now O(N//2 + 1), which is O(N).

Coin Change Algorithm - DP with 1D array

I came across a solution to the Coin Change problem here : Coin Change. Here I was able to understand the first recursive method, the second method which uses DP with a 2D array. But am not able to understand the logic behind the third solution.
As far as I have thought, the last method works for problems in which the sequence of coins used in coin change is considered. Am I correct? Can anyone please explain me if I am wrong.
Well I figured it out myself!
This can be easily proved using induction. Let table[k] denote the ways change can be given for a total of k. Now the algorithm consists of two loops, one which is controlled by i and iterates through the array containing all the different coins and the other is the j controlled loop which for a given i, updates all the values of elements in array table. Now consider for a fixed i we have calculated the number of ways change can be given for all values from 1 to n and these values are stored in table from table[1] to table[n]. When the i controlled loop iterates for i+1, the value in table[j] for an arbitrary j is incremented by table[j-S[i + 1]] which is nothing but the ways we can create j using at least one coin with value S[i + 1] (the array which stores coin values). Thus the total value in table[j] equals the number of ways we can create a change with coins of value S[1]....S[i] (this was already stored before) and the value table[j-S[i + 1]]. This is same as the optimal substructure of the problem used in the recursive algorithm.
int arr[size];
memset(arr,0,sizeof(size));
int n;
cin>>n;
int sum;
cin>>sum;
int a[size];
fi(i,n)
cin>>a[i];
arr[0]=1;
fi(i,n)
for(int j=arr[i]; j<=n; j++)
a[j]+=a[j-arr[i]];
cout<<arr[n];
The array arr is initialised as 0 so as to show that the number of ways a sum of ican be represented is zero(that is not initialised). However, the number of ways in which a sum of 0 can be represented is 1 (zero way).
Further, we take each coin and start initialising each position in the array starting from the coin denomination.
a[j]+=a[j-arr[i]] means that we are basically incrementing the possible ways to represent the sum jby the previous number of ways, required (j-arr[i]).
In the end, we output the a[n]

Binary search - worst/avg case

I'm finding it difficult to understand why/how the worst and average case for searching for a key in an array/list using binary search is O(log(n)).
log(1,000,000) is only 6. log(1,000,000,000) is only 9 - I get that, but I don't understand the explanation. If one did not test it, how do we know that the avg/worst case is actually log(n)?
I hope you guys understand what I'm trying to say. If not, please let me know and I'll try to explain it differently.
Worst case
Every time the binary search code makes a decision, it eliminates half of the remaining elements from consideration. So you're dividing the number of elements by 2 with each decision.
How many times can you divide by 2 before you are down to only a single element? If n is the starting number of elements and x is the number of times you divide by 2, we can write this as:
n / (2 * 2 * 2 * ... * 2) = 1 [the '2' is repeated x times]
or, equivalently,
n / 2^x = 1
or, equivalently,
n = 2^x
So log base 2 of n gives you x, which is the number of decisions being made.
Finally, you might ask, if I used log base 2, why is it also OK to write it as log base 10, as you have done? The base does not matter because the difference is only a constant factor which is "ignored" by Big O notation.
Average case
I see that you also asked about the average case. Consider:
There is only one element in the array that can be found on the first try.
There are only two elements that can be found on the second try. (Because after the first try, we chose either the right half or the left half.)
There are only four elements that can be found on the third try.
You can see the pattern: 1, 2, 4, 8, ... , n/2. To express the same pattern going in the other direction:
Half the elements take the maximum number of decisions to find.
A quarter of the elements take one fewer decision to find.
etc.
Since half of the elements take the maximum amount of time, it doesn't matter how much less time the other elements take. We could assume that all elements take the maximum amount of time, and even if half of them actually take 0 time, our assumption would not be more than double whatever the true average is. We can ignore "double" since it is a constant factor. So the average case is the same as the worst case, as far as Big O notation is concerned.
For binary search, the array should be arranged in ascending or descending order.
In each step, the algorithm compares the search key value with the key value of the middle element of the array.
If the keys match, then a matching element has been found and its index, or position, is returned.
Otherwise, if the search key is less than the middle element's key, then the algorithm repeats its action on the sub-array to the left of the middle element.
Or, if the search key is greater,then the algorithm repeats its action on the sub-array to the right.
If the remaining array to be searched is empty, then the key cannot be found in the array and a special "not found" indication is returned.
So, a binary search is a dichotomic divide and conquer search algorithm. Thereby it takes logarithmic time for performing the search operation as the elements are reduced by half in each of the iteration.
For sorted lists which we can do a binary search, each "decision" made by the binary search compares your key to the middle element, if greater it takes the right half of the list, if less it will take the left half of the list (if it's a match it will return the element at that position) you effectively reduce your list by half for every decision yielding O(logn).
Binary search however, only works for sorted lists. For un-sorted lists you can do a straight search starting with the first element yielding a complexity of O(n).
O(logn) < O(n)
Although it entirely depends on how many searches you'll be doing, your inputs, etc what your best approach would be.
For Binary search the prerequisite is a sorted array as input.
• As the list is sorted:
• Certainly we don't have to check every word in the dictionary to look up a word.
• A basic strategy is to repeatedly halve our search range until we find the value.
• For example, look for 5 in the list of 9 #s below.v = 1 1 3 5 8 10 18 33 42
• We would first start in the middle: 8
• Since 5<8, we know we can look at just the first half: 1 1 3 5
• Looking at the middle # again, narrow down to 3 5
• Then we stop when we're down to one #: 5
How many comparison is needed: 4 =log(base 2)(9-1)=O(log(base2)n)
int binary_search (vector<int> v, int val) {
int from = 0;
int to = v.size()-1;
int mid;
while (from <= to) {
mid = (from+to)/2;
if (val == v[mid])
return mid;
else if (val > v[mid])
from = mid+1;
else
to = mid-1;
}
return -1;
}

Consecutive subset product

I got this as an interview question and was thinking on how to solve it.
Lets say a number is an array ={7,6,3} and its consequtive substring ares {7},{6},{3},{7,6},{6,3},{7,6,3}({7,3} is not valid) check if product of any two subsets are equal).
so {6,2,3} fails as {6}={2*3}
can anyone give me a nudge in right direction.
If there are n numbers in the array. So there are n * (n - 1) / 2 consequtive subsets. You can pre-process thess subsets' product, and insert into a map. Then enum the subsets to find if the product have more than twice in the map. Then you can solve this question.

Resources