I was solving this problem :http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=286&page=show_problem&problem=3268
and I am stuck and can't find any hints.
The question:
You will be given an integer n ( n<=10^9 ) now you have to tell how many
distinct sets of integers are there such that each number from 1 to n can
be generated uniquely from a set. Also sum of set should be n. eg for n=5 , one such set is:
{1,2,2} as
1 can be generated only by { 1 }
2 by { 2 }
3 by {1,2} ( note the two 2's are indistinguishable)
4 by {2,2}
5 by {1,2,2}
for generating a number each number of a set can be used only once. ie for above set
we can't do {1,1} to generate 2 as only one 1 is there.
Also the set {1,2,2} is equivalent to {2,1,2} ie sets are unordered.
My approach:
The conclusion I came to was. Let F(S,k) denote number desired sets of sum S whose
largest element is k.Then to construct a valid set we can take two paths from this
state.Either to F(S+k,k) or to F(2*S+1,S+1).I keep a count of how many times I come
to state where S=n(the desired sum) and do not go further if S becomes > n.This is
clearly bruteforce which I just wrote to see if my logic was correct(which is correct)
.But this will give time limit exceed . How do I improve my approach??I have a
feeling it is done by dp/memoization.
This is a known integer sequence.
Spoilers: http://oeis.org/A002033
Related
We know 3 things
n(number of elements in the set)
k(no. of parts)
set s= {x,x,x,x,...,x(n times)} (here X can have any possible integral value)
we have to find the result as a number which will holds the value of number of distinct partitions possible of the set S.
Is there any kind way(formula / procedure) to find the result using given values?
EXAMPLES:
Input: n = 3, k = 2
Output: 4
Explanation: Let the set be {0,0,0} (assuming x=0), we can partition
it into 2 subsets in following ways
{{0,0}, {0}}, {{0}, {0,0}}, {{0,0,0},{}}
{{},{0,0,0}}.
further, see {{0,0}, {0}} is made up of 2 subsets namely {0,0}
and {0} And it has x(=0) used exactly n(=3) times
Input: n = 3, k = 1
Output: 1
Explanation: There is only one way {{1, 1, 1}} (assuming x=1)
Note:
I know I used word Set in the problem. but a set is defined as collection of distinct elements. So you can either consider it a Multiset, an array or You can assume a set can hold same elements for this particular problem.
I am just trying to use Same terminology as that in the problem.
I have an array of size n and I can apply any number of operations(zero included) on it. In an operation, I can take any two elements and replace them with the absolute difference of the two elements. We have to find the minimum possible element that can be generated using the operation. (n<1000)
Here's an example of how operation works. Let the array be [1,3,4]. Applying operation on 1,3 gives [2,4] as the new array.
Ex: 2 6 11 3 => ans = 0
This is because 11-6 = 5 and 5-3 = 2 and 2-2 = 0
Ex: 20 6 4 => ans = 2
Ex: 2 6 10 14 => ans = 0
Ex: 2 6 10 => ans = 2
Can anyone tell me how can I approach this problem?
Edit:
We can use recursion to generate all possible cases and pick the minimum element from them. This would have complexity of O(n^2 !).
Another approach I tried is Sorting the array and then making a recursion call where the either starting from 0 or 1, I apply the operations on all consecutive elements. This will continue till their is only one element left in the array and we can return the minimum at any point in the recursion. This will have a complexity of O(n^2) but doesn't necessarily give the right answer.
Ex: 2 6 10 15 => (4 5) & (2 4 15) => (1) & (2 15) & (2 11) => (13) & (9). The minimum of this will be 1 which is the answer.
When you choose two elements for the operation, you subtract the smaller one from the bigger one. So if you choose 1 and 7, the result is 7 - 1 = 6.
Now having 2 6 and 8 you can do:
8 - 2 -> 6 and then 6 - 6 = 0
You may also write it like this: 8 - 2 - 6 = 0
Let"s consider different operation: you can take two elements and replace them by their sum or their difference.
Even though you can obtain completely different values using the new operation, the absolute value of the element closest to 0 will be exactly the same as using the old one.
First, let's try to solve this problem using the new operations, then we'll make sure that the answer is indeed the same as using the old ones.
What you are trying to do is to choose two nonintersecting subsets of initial array, then from sum of all the elements from the first set subtract sum of all the elements from the second one. You want to find two such subsets that the result is closest possible to 0. That is an NP problem and one can efficiently solve it using pseudopolynomial algorithm similar to the knapsack problem in O(n * sum of all elements)
Each element of initial array can either belong to the positive set (set which sum you subtract from), negative set (set which sum you subtract) or none of them. In different words: each element you can either add to the result, subtract from the result or leave untouched. Let's say we already calculated all obtainable values using elements from the first one to the i-th one. Now we consider i+1-th element. We can take any of the obtainable values and increase it or decrease it by the value of i+1-th element. After doing that with all the elements we get all possible values obtainable from that array. Then we choose one which is closest to 0.
Now the harder part, why is it always a correct answer?
Let's consider positive and negative sets from which we obtain minimal result. We want to achieve it using initial operations. Let's say that there are more elements in the negative set than in the positive set (otherwise swap them).
What if we have only one element in the positive set and only one element in the negative set? Then absolute value of their difference is equal to the value obtained by using our operation on it.
What if we have one element in the positive set and two in the negative one?
1) One of the negative elements is smaller than the positive element - then we just take them and use the operation on them. The result of it is a new element in the positive set. Then we have the previous case.
2) Both negative elements are smaller than the positive one. Then if we remove bigger element from the negative set we get the result closer to 0, so this case is impossible to happen.
Let's say we have n elements in the positive set and m elements in the negative set (n <= m) and we are able to obtain the absolute value of difference of their sums (let's call it x) by using some operations. Now let's add an element to the negative set. If the difference before adding new element was negative, decreasing it by any other number makes it smaller, that is farther from 0, so it is impossible. So the difference must have been positive. Then we can use our operation on x and the new element to get the result.
Now second case: let's say we have n elements in the positive set and m elements in the negative set (n < m) and we are able to obtain the absolute value of difference of their sums (again let's call it x) by using some operations. Now we add new element to the positive set. Similarly, the difference must have been negative, so x is in the negative set. Then we obtain the result by doing the operation on x and the new element.
Using induction we can prove that the answer is always correct.
You are given an array of integers. You can divide this array into two distinct groups and that groups must have most approapiate sum( the difference beetween the sum of that two groups needs to be as low as possible in modul). The output need to contain the sum of each of two groups. For example: if n = 5 and the array is {2,8,10,1,3} the output needs to be 12 and 12 (12 = 2 + 10 and 12 = 8 + 1 + 3). Is there any faster solution than backtracking?
What you describe is called the Partition Problem (optimization version) which is NP hard, so you won't find an efficient algorithm that always gives you an exact result. However there are approximate solutions that work very well in practice.
One example is the greedy algorithm, which sorts the input array and then fills up the two output arrays, starting with the greatest value, as follows:
(1) Put first value to out1
(2) fill up out2 until sum(out2) > sum(out1), exit if no more items
(3) fill up out1 until sum(out1) > sum(out2), exit if no more items
(4) resume with (2)
I am developing a probability analysis program for a board game. As part of an algorithm* I need to calculate the possible permutations of partitions of a number (plus some padding), such that all partition components cannot occupy any position that is lower than the total length of the permutation, in digits, minus the value of the component.
(It is extremely unlikely, however, that the number that will be partitioned will ever be higher than 8, and the length of the permutations will never be higher than 7.)
For instance, say I have the partition of 4, "211", and I want to find the permutations when there is a padding of 2, i.e. length of 5:
0 1 2 3 4 (array indexes)
5 4 3 2 1 (maximum value of partition component that can be allocated to each index)
2 1 1 _ _ (the partition plus 2 empty indexes)
This is represented as an array like so {2,1,1,0,0}
There are 6 permutations when 2 is in the 0 index (4! / 2! 2!), and there are 4 indexes that 2 can occupy (2 cannot be placed into the last index) so overall there are 24 permutations for this case (a 1 can occupy any index).
The output for input "21100":
21100, 21010, 21001, 20110, 20101, 20011
02110, 02101, 02011, 12100, 12010, 12001
00211, 10210, 11200, 10201, 01210, 01201
10021, 01021, 00121, 11020, 10120
01120
Note that this is simply the set of all permutations of "21100" minus those where 2 is in the 4th index. This is a relatively simple case.
The problem can be described as combining n different permutation groups, as the above case can be expressed as the combining of the permutations of x=1 n=4 and those of x=2 n=5, where x is the value count and n is the "space" count.
My difficulty is formulating a method that can obtain all possibilities computationally, and any advice would be greatly appreciated. -Please excuse any muddling of terminology in my question.
*The algorithm answers the following question:
There is a set of n units that are attacked k times. Each
attack has p chance to miss and q (1 - p) chance to damage
a random unit from the set. A unit that is damaged for a second time is destroyed
and is removed from the set.
What is the probability of there being
x undamaged units, y damaged units and z destroyed units after the attacks?
If anyone knows a more direct approach to this problem, please let me know.
I am going to use the algorithm to generate all permutations of the multiset as given in the answer to this question
How to generate all the permutations of a multiset?
and then filter to fit my criteria.
How would you implement a random number generator that, given an interval, (randomly) generates all numbers in that interval, without any repetition?
It should consume as little time and memory as possible.
Example in a just-invented C#-ruby-ish pseudocode:
interval = new Interval(0,9)
rg = new RandomGenerator(interval);
count = interval.Count // equals 10
count.times.do{
print rg.GetNext() + " "
}
This should output something like :
1 4 3 2 7 5 0 9 8 6
Fill an array with the interval, and then shuffle it.
The standard way to shuffle an array of N elements is to pick a random number between 0 and N-1 (say R), and swap item[R] with item[N]. Then subtract one from N, and repeat until you reach N =1.
This has come up before. Try using a linear feedback shift register.
One suggestion, but it's memory intensive:
The generator builds a list of all numbers in the interval, then shuffles it.
A very efficient way to shuffle an array of numbers where each index is unique comes from image processing and is used when applying techniques like pixel-dissolve.
Basically you start with an ordered 2D array and then shift columns and rows. Those permutations are by the way easy to implement, you can even have one exact method that will yield the resulting value at x,y after n permutations.
The basic technique, described on a 3x3 grid:
1) Start with an ordered list, each number may exist only once
0 1 2
3 4 5
6 7 8
2) Pick a row/column you want to shuffle, advance it one step. In this case, i am shifting the second row one to the right.
0 1 2
5 3 4
6 7 8
3) Pick a row/column you want to shuffle... I suffle the second column one down.
0 7 2
5 1 4
6 3 8
4) Pick ... For instance, first row, one to the left.
2 0 7
5 1 4
6 3 8
You can repeat those steps as often as you want. You can always do this kind of transformation also on a 1D array. So your result would be now [2, 0, 7, 5, 1, 4, 6, 3, 8].
An occasionally useful alternative to the shuffle approach is to use a subscriptable set container. At each step, choose a random number 0 <= n < count. Extract the nth item from the set.
The main problem is that typical containers can't handle this efficiently. I have used it with bit-vectors, but it only works well if the largest possible member is reasonably small, due to the linear scanning of the bitvector needed to find the nth set bit.
99% of the time, the best approach is to shuffle as others have suggested.
EDIT
I missed the fact that a simple array is a good "set" data structure - don't ask me why, I've used it before. The "trick" is that you don't care whether the items in the array are sorted or not. At each step, you choose one randomly and extract it. To fill the empty slot (without having to shift an average half of your items one step down) you just move the current end item into the empty slot in constant time, then reduce the size of the array by one.
For example...
class remaining_items_queue
{
private:
std::vector<int> m_Items;
public:
...
bool Extract (int &p_Item); // return false if items already exhausted
};
bool remaining_items_queue::Extract (int &p_Item)
{
if (m_Items.size () == 0) return false;
int l_Random = Random_Num (m_Items.size ());
// Random_Num written to give 0 <= result < parameter
p_Item = m_Items [l_Random];
m_Items [l_Random] = m_Items.back ();
m_Items.pop_back ();
}
The trick is to get a random number generator that gives (with a reasonably even distribution) numbers in the range 0 to n-1 where n is potentially different each time. Most standard random generators give a fixed range. Although the following DOESN'T give an even distribution, it is often good enough...
int Random_Num (int p)
{
return (std::rand () % p);
}
std::rand returns random values in the range 0 <= x < RAND_MAX, where RAND_MAX is implementation defined.
Take all numbers in the interval, put them to list/array
Shuffle the list/array
Loop over the list/array
One way is to generate an ordered list (0-9) in your example.
Then use the random function to select an item from the list. Remove the item from the original list and add it to the tail of new one.
The process is finished when the original list is empty.
Output the new list.
You can use a linear congruential generator with parameters chosen randomly but so that it generates the full period. You need to be careful, because the quality of the random numbers may be bad, depending on the parameters.