Efficient algorithm for finding max number of pairs [duplicate] - c++

This question already has answers here:
Choosing mutually exclusive pairs efficiently
(4 answers)
Closed 7 years ago.
What would be the fastest way to find pairs of numbers from a list of pair of numbers such that maximum number of pairs are formed?
For e.g: I have 6 numbers: 0, 1, 2, 3, 4, 5
Following are the valid pairs:
0 1
0 2
0 3
1 4
3 5
Now, once a number is included in a pair, the number cannot be included in another pair.
That is, if I chose the pair 0 1, I cannot again chose 0 2 as I have already used 0 once.
I need to choose pairs from the list of valid pairs such that I get maximum number of pairs.
As per the example:
If I choose the following pairs:
0 1
3 5
Note that I'll be able to chose only these two pairs such that no number is repeated and 2 and 4 will be left.
But If I choose the following pairs:
0 2
1 4
3 5
I get three pairs and no number is left alone. Similarly from a given list, I need to calculate the maximum number of pairs I can make. What would be the most efficient way to do it?

This problem can be solved in polynomial time complexity using Bloossom algorithm:
http://en.wikipedia.org/wiki/Blossom_algorithm
Form a graph where each number is node and connect each pair with edge. Run the above mentioned algorithm on this graph to find solution.

So your valid pairs could be represented as a graph, and then the maximum number of pairs is a maximum matching in that graph.
Note that you can have multiple solutions. For valid pairs [(0,1),(1,2),(2,3),(3,4)] both [(0, 1), (2, 3)] and [(1, 2), (3, 4)] are solutions.

Related

Find how many numbers meet the constraints in a range

Given 2 integers l and r, calculate how many numbers in [l, r] that meet these constraints
1) The number should be divisible by 7
2) The number contains at least three digit 7
3) The number contains more digit 7 than digit 4
777, 774746 meet those constraints, 7771, 77, 747474 are not.
Using brute force can easily find the answer but when the range is very large then it might take a lot of time.
I think dynamic programming can help to solve this problem, but i can't think of the solution
Can someone give me some guide?
Taking from the original brute-force version:
Iterate with i over numbers between [l,r]
Use modulo to check if i is divisible by 7
Use modulo and division to get counts of digits in i
digit_count(7) >= 3
digit_count(7) > digit_count(4)
here's some ideas I came up with...
1. Use only multiples of 7, implicitly fulfilling the first criterion:
This one is really simple. We can improve this to only use i that is divisible by 7. If I give you a number x and ask you to generate me numbers divisible by n until you reach y, then you'd best do:
for (auto i = x + x % n; i < y; i += n)
So for the case of multiples of 7 between l and r, all you need to do is run the loop for (auto i = l + l % 7; i < r; i += 7) This will give you 7x speed-up from the brute-force version.
2. Remember the digit counts
There's no need to execute numerous divisions and modulos to get you the count of digits of each number you go through. Since you know by how much you increment, you also know what digits change to what. This way, you'd only need to split into digits the starting number (e.g. l % 7 + l).
Now what we'd be storing isn't the count of digits but actually something very much resembling BCDs - an array of digits that represent the number we are currently working with. You'd then get something like std::vector<int> expressing the array of [7, 7, 2, 4, 5, 7] for number 772457. Now all you need to do is to use the BCD arithmetic inside the array every time you increment the loop counter, going [7, 7, 2, 4, 5, 7] + 6 = [7, 7, 2, 4, 6, 3].
The other thing we'd need to store are two ints - sevens and fours. In the intitialization phase, once you "disintegrate" the first number into the array, you'd just go through it and increment sevens for each 7, fours for each 4. And you'd just keep this numbers up to date: with each update of the array, you'd decrement fours for each 4 you took away and increment it for each 4 you created in the array. And the same for number 7. You can then compare sevens >= 3 && sevens > fours and know the result fast.
Funny thing is, that this gives you no theoretical improvement in the complexity and it might not work, but I suspect it should... It's quite a lot of code so I'm not going to provide it. You might end up working with the BCD array inverted or starting with the r end of iteration range so you don't need to resize the array. And maybe you can come up with many more improvements and tweaks. However, I have strong doubt that the solution can be made asymptotically less complex this way.
3. More thoughts
Now this wasn't dynamic programming at all. Or was it? If you think about it, I have a gut feeling that this idea of an array of numbers as BCD can now be converted to a problem where you look for permutations containing a given combination. You can make a graph out of it and search it. And that's where you'd go dynamic. I'm afraid, however, that this would make for quite a longer post...
But I already got the first doubt about that and that's the check for divisibility by 7 which would then be applied to all the numbers that are found in the graph (the graph would only support criterions 2 and 3 by its nature and yield all numbers containing the combinations). So in the end, it boils down to sizes of ranges that should be supported by the alrgorithm and the ratio of numbers fulfilling the first criterion and the numbers fulfilling the second and third ones in those ranges.
EDIT:
I have since found that my idea of computing the count of numbers fitting the criteria is incorrect. Some small comparisons table:
| range | numbers f/ c2 | c2_groups | c2_total | c1_total |
| 0 - 1k | 777 | 1 | 1 | ~143 |
| 1k - 10k | _777, 7_77, 77_7, 777_ | 4 | 40 | ~1286 |
| 10k - 100k | __777, _7_77, ... | 10 | 1000 | ~12857 |
Where numbers f/ c2 are numbers fulfilling criterion 2, c2_groups is count of possible combinations of any digit and 7s in the number, cx_total is total count of numbers fulfilling criterion x in the range.
Having that, it looks like it's quite questionable whether it would be efficient to filter by the number of digits criteria first. I suppose that would require some mathematical analysis that would take longer than implement the solution...
Space search
With having state equivalent to method #2, it is possible to do DFS in the numbers range. Instead of incrementing by 7, it would store a digits vector and increment values in it based on an offset that would be movable, e.g.
increment [1, 0, 7, _] -> [1, 0, 8, _]
^ ^
This is what the algorithm will be doing in the core loop. You can then check whether the current digits vector setup can fulfill the criteria - e.g. [0, p, _, _] can fulfill them, while [0, 0, p, _] cannot (p is the element that is being pointed to). This way, you will keep incrementing the highest possible digit, skipping a lot of numbers. Every time there is a possibility to fulfill the requirements, you will increment the offset and repeat the process:
push [7, 7, _, _] -> [7, 7, 0, _]
^ ^
Once you're at the least significant digit position, you'll also start checking the divisibility by 7 of each candidate. You can try either converting the digits to int and using modulo or using some sort of divisibility algorithm (these use digits so that's a pleasant coincidence).
This way, you'll get a number that passes all criteria and return it. Now you might come to a situation where you exhaust all the digits in given digit range. In that case, you need to move the offset one place back:
pop [7, 7, 7, 9] -> [7, 7, 7, _]
^ ^
Now, you'd use increment, see that [7, 7, 8, _] can fulfill the criteria and push again. Then run through 0, 1, 2, ... sequence until you come to 7, see that 7787 is ok with both 2nd and 3rd criteria but fails division by 7. And so on...
You'll also need to check whether you're not already over the r limit. I guess that can be done in quite a sane manner by splitting r to digits as well and comparing it from the most significant digit.
Given that we have no math analysis for this, and that this is still going through quite a lot of numbers (especially in case that 7 is the least significant digit), I wonder whether this is really worth implementing. But it's not something super-complex either. Good luck!
For 1: if(yourint % 7 == 0)
For 2: check this link split int into digits, check if digit equals 7 and count to 3.
For 3: expend link 2 with an if a digit equals 7 or 4 than counter++
At the end you should check your counters (7 an 4) which one is the highest.

Using Dynamic Programming To Group Numbers

Let's say you have a group of numbers. You need to eliminate numbers until there is only one left. This is hard to explain, so let me provide you with an example.
The numbers are 3, 6, 9, and 10.
You pair 3 with 9. You eliminate 3. (Note: either one of them could be eliminated). Now there are 6, 9, and 10 left. You pair 6 with 9. You eliminate 9. Now there are 6 and 10 left. You pair 6 with 10 (only option).
The problem is: I want to find the maximum value obtained from this elimination. Each time a number is eliminated, the XOR value of those two numbers is added to the count. In the previous example, the total value would be (3 ^ 6) + (6 ^ 9) + (6 ^ 10) = 10 + 15 + 12 = 37. This happens to be the maximum value that can be obtained from any elimination combination.
How would I solve this problem in Java with 2000 numbers? I know I can find every possible combination using brute force, but the run time of this was more than two seconds, and I prefer my solutions to be under two seconds. The only option left is Dynamic Programming.
Does anyone know how to solve this with Dynamic Programming?

Generate random list of numbers that add up to 1 [duplicate]

This question already has answers here:
Getting N random numbers whose sum is M
(9 answers)
Closed 9 years ago.
Are there any STL functions that allow one to create a vector with random numbers that add up to 1? Ideally, this would be dependent on the size of the vector, so that I can make the vector size, say, 23 and this function will populate those 23 elements with random numbers between 0 and 1 that all add up to 1.
One option would be to use generate to fill the vector with random numbers, then using accumulate to sum up the values, and finally dividing all the values in the vector by the sum to normalize the sum to one. This is shown here:
std::vector<double> vec(23);
std::generate(vec.begin(), vec.end(), /* some random source */);
const double total = std::accumulate(vec.begin(), vec.end(), 0.0);
for (double& value: vec) value /= total;
Hope this helps!
No, but you can do this easily with the following steps:
Fill the vector with random float values, say 0 to 100.
Calculate the sum.
Divide each value by the sum.
There are certainly lots of standard functions to generate random numbers. To get the normalization to happen, you'll want to do that after you've generated all the numbers. (For instance, you might generate the numbers, then divide them all by their sum.) Note that you probably won't have uniformly-distributed numbers at that point, if it matters.
This depends on the kind of distribution of random numbers that you want. One approach (which has been suggested in another answer) is to just generate some random numbers, then divide them each by their total sum.
Another approach is to make a list of random numbers from the interval [0, 1), then sort them. You can then take the differences between consecutive numbers (adding 0 and 1 to the beginning and end of your list respectively). These differences will naturally sum up to 1. So, for example, let's say you picked 3 random numbers and they were: {0.38, 0.05, 0.96}. Let's add 0 and 1 to this list and then sort it:
{0, 0.05, 0.38, 0.96, 1}
Now let's take the differences:
{0.05, 0.33, 0.58, 0.04}
If you add these up, they sum to 1. If you don't understand why this works, imagine you have a piece of rope of length 1 and you use a knife to cut it some random distance from the end (without moving the pieces apart as you cut it). Naturally all the pieces will add up to the original length. That's exactly what's happening here.
Now, like I said, this approach will give you a different distribution of random numbers than the divide by sum method, so don't consider them to be the same!

Generating permutations which are not mirrors of each other

I want to generate permutations of n numbers, where there is no two permutations which are reversions of each other (the first one read from the last character to the first is the same as the second one). For instance, n = 3, I want to generate:
1 2 3 //but not 3 2 1
1 3 2 //but not 2 3 1
2 1 3 //but not 3 1 2
I do not care which one of the two will be generated. The algorith should be applicable for large n (>20). Is there any such algorithm or a way to check if the generated permutations is a mirror of previously generated one?
Use std::next_permutation and ignore permutations whose first element is larger than its last.
No, By usual hardware and software upto this days, you cannot do this, because the number of such a permutations is 20!/2 > 10^10 * 2^20, means you need many years to generate them.

Creating a list of the different numbers that occur in a 2D array using the GPU

Given a 2D array of integers, for example
3 3 1 1 1
3 3 3 1 1
3 3 3 3 1
3 3 3 2 2
3 3 7 2 2
is there an efficient GPU algorithm, that produces a list of all occuring numbers?
For example
1 2 3 7
for the 2d array above.
The list does not need to be sorted (so 3 2 1 7 for example would be okay as well).
Assuming there isn't too large of a range of integers to be dealt with (and that these are non-negative integers) you can make a new array that has the length of the range of possible integers in your original array with values initialized to zero.
Then, when a thread finds a number it increments that index of the array by one (so if we see the integer 4 we do something like result[4]++. We won't need to sync here since all we'll care about is whether or not a given index of this result array has a value of zero or not.
Of course this can be done if we'll expect negative integers as well - we'll just need twice the space in our result array.