I am trying to help someone write a program that I thought would be easy, but of course it never is :)
I am trying to take a class roster (usually between 10-20 students) and effectivly uniquely pair off each classmate to another to make unique groups. Therefore in a class of 10 people, you can have 9 groups.
It needs to be able to handle odd number of students too, adding to my confusion.
I was looking at doing this in Java, but that is flexible. Any ideas on an algorithmic way to guarantee a)not infinite looping (ending with 2 people who have already been partners) and b) I am aiming for more efficent time than space, since class size will be small!
Thanks!
You want to create a complete graph with each student as a node, then randomly select edges and insert them into a unique set.
On the next "pull", you want to do the same thing, except now if the edge has already been selected, discard and reselect.
Here is C# code which solves the question.
I've assumed that you really care about maximizing the uniqueness in student pairing, not the set of possible unique groups of student pairings.
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
namespace Pairing
{
class Program
{
static void Main(string[] args)
{
//switch these lines if you'd prefer a command line interface to a text file.
var rgs = File.ReadAllLines("Roster.txt");
//var rgs = args;
var setPairs = new HashSet<HashSet<string>>();
for (var ixrgs = 0; ixrgs < rgs.Length - 1; ixrgs++)
for (var ixrgsSubset = ixrgs + 1; ixrgsSubset < rgs.Length; ixrgsSubset++)
setPairs.Add(new HashSet<string>(new string[] { rgs[ixrgs], rgs[ixrgsSubset] }));
var setGroups = new HashSet<HashSet<HashSet<string>>>();
var setUsedPairs = new HashSet<HashSet<string>>();
while (setPairs.Count > 0)
{
var setPairsTmp = new HashSet<HashSet<string>>(setPairs);
var setTmp = new HashSet<HashSet<string>>();
var setUsedVariables = new HashSet<string>();
while (setPairsTmp.Count > 0)
{
//give me the first element
var pair = setPairsTmp.First<HashSet<string>>();
//store it
setTmp.Add(pair);
//add it to our set of used variables
setUsedVariables.UnionWith(pair);
//remove it from our set of available pairs.
setPairsTmp.RemoveWhere(set => set.Intersect<string> (setUsedVariables).Count<string>() != 0);
//remove its implicated deadlocks from our set of available pairs
//(this step is both gross, and key. Without it, failure potential arises.)
var s1 = new HashSet<string>();
var s2 = new HashSet<string>();
//get the set of variables paired with the first:
var rgPair = pair.ToArray<string>();
foreach (var set in setUsedPairs)
{
if (set.Contains(rgPair[0]))
s1.UnionWith(set);
if(set.Contains(rgPair[1]))
s2.UnionWith(set);
}
s1.IntersectWith(s2);
//enumerate the pairs created by the deadlocking pairs, remove them from our available selections.
var rgsTmp = s1.ToArray<string>();
for (var ixrgs = 0; ixrgs < rgsTmp.Length - 1; ixrgs++)
for (var ixrgsSubset = ixrgs + 1; ixrgsSubset < rgsTmp.Length; ixrgsSubset++)
setPairsTmp.RemoveWhere(set => set.Contains(rgsTmp[ixrgs]) && set.Contains(rgsTmp[ixrgsSubset]));
}
setPairs.ExceptWith(setTmp);
setGroups.Add(setTmp);
setUsedPairs.UnionWith(setTmp);
}
//at this point, setGroups contains the set of unique group combinations.
//the non-maximally sized groups indicate unique sets that could form provided that
//all other students are in redundant sets.
var enumerableGroups = setGroups.OrderByDescending<HashSet<HashSet<string>>, int>(set => set.Count);
//Sanity Check:
foreach (var group in enumerableGroups)
{
Console.Write("{");
foreach (var pair in group)
Console.Write(string.Format(#"[{0},{1}]", pair.ToArray<string>()));
Console.WriteLine("}");
}
}
}
}
This is an unusual answer for me - to say "download an application" - but here you go:
What you describe may be similar enough to Chess Tournament Pairing.
Check this out: http://home.swipnet.se/rullchef/chessp/
Here's an explanation of the Monrad system which may be what you're after:
Monrad System
The Monrad system is a very interesting variation of the cup system, which to my knowledge is only used on a regular basis in chess tournaments. In the first round all teams are paired randomly. The winner gets 1 point and the looser zero. In each successive round all teams with the same number of points are paired randomly (except that teams which earlier have played each other can not be paired if there are other pairing possibilities). This system has the advantage, that all teams keep playing, in contrast to the cup system, and as the season (or tournament) advances teams with equal strength will be meeting each other. There are no limitations to the number of rounds that can be played, but eventually teams have to be paired if they have similar, but not necessarily identical, number of points. The team with the largest number of points after a predefined set of rounds is the winner.
Here's the pseudocode for Vlion's answer above. This isn't the fastest way to do it but it's an illustration of the concept (thanks Vlion!)
// create all the edges
for i := 1 to number_of_students - 1
for j := i + 1 to number_of_students
edges.add(new Edge(i,j))
// select all groups from the edges
for x := 1 to number_of_students - 1
used_nodes.clear
group.clear
for y := 1 to number_of_students div 2
do
current_edge = edges.get_next
while (current_edge.n1 not in used_nodes) and
(current_edge.n2 not in used_nodes)
used_nodes.add(current_edge.n1)
used_nodes.add(current_edge.n2)
group.add(current_edge)
edges.remove(current_edge)
groups.add(group)
The algorithm you are asking for seems more or less the same as the algorithm for preparing schedules for round-robin tournaments. The details can be found in this Wikipedia article. You can also use generators lying around on the web for a quick tryout. One of them can be found here.
I don't know if it's exactly what you asked for, but here my take on it in simple python.
It spits out each unique grouping you can have for (in my example) 10 students.
It is not the fastest thing there is i guess, but its very easy to implement and to follow.
from itertools import permutations
def my_sort(x):
assert type(x) in (tuple, list)
assert len(x)==10
groups = x[0:2],x[2:4],x[4:6],x[6:8],x[8:10]
groups = sorted([sorted(g) for g in groups], key=lambda k:k[0])
return tuple(x for g in groups for x in g )
S = set(my_sort(p) for p in permutations(list(range(10))))
"""
len(S) == 945
list(sorted(S))[-3:] == [(0, 9, 1, 8, 2, 7, 3, 4, 5, 6), (0, 9, 1, 8, 2, 7, 3, 5, 4, 6), (0, 9, 1, 8, 2, 7, 3, 6, 4, 5)]
"""
a tuple represents all groups in a row:
(0, 9, 1, 8, 2, 7, 3, 4, 5, 6) means 0 is grouped with 9, 1 is grouped with 8 and so on.
Related
I am trying to pick one number from multiple arraylists and find all possible ways to pick the numbers such that the sum of those numbers is greater than a given number. I can only think of brute force implementation.
For example, I have five arraylists such as
A = [2, 6, 7]
B = [6, 9]
C = [4]
D = [4, 7]
E = [8, 10, 15]
and a given number is 40.
Then after picking one number from each list, all possible ways could be
[7, 9, 4, 7, 15]
[6, 9, 4, 7, 15]
So, these are the two possible ways to pick numbers greater than or equal to 40. In case the given number is small then there could be many solutions. So how can I count them without brute force? Even with brute force how do I devise the solution in Java.
Below is my implementation. It works fine for small numbers but if the numbers are large then it gives me runtime error since the program runs for too long.
public static void numberOfWays(List<Integer> A, List<Integer> B, List<Integer> C, List<Integer> D,
List<Integer> E, int k){
long ways = 0;
for(Integer a:A){
for(Integer b:B){
for(Integer c:C){
for(Integer d:D){
for(Integer e:E){
int sum = a+b+c+d+e;
//System.out.println(a+" "+b+" "+c+" "+d+" "+e+" "+sum);
if(sum > k)
ways++;
}
}
}
}
}
System.out.println(ways);
}
The list can contain up to 1000 elements and the elements can range from 1 to 1000. The threshold value k can range from 1 to 10^9.
I am not a java programmer.But I think its a logical problem.So,I have solved it for you in python.I am pretty sure you can convert it into java.
Here is the code:
x = input('Enter the number:')
a = [2, 6, 7]
b = [6, 9]
c = [4]
d = [4, 7]
e = [8, 10, 15]
i = 0
z = 0
final_list = []
while i <= int(x):
try:
i += a[z]
final_list.append(a[z])
except BaseException:
pass
try:
i += b[z]
final_list.append(b[z])
except BaseException:
pass
try:
i += c[z]
final_list.append(c[z])
except BaseException:
pass
try:
i += d[z]
final_list.append(d[z])
except BaseException:
pass
try:
i += e[z]
final_list.append(e[z])
except BaseException:
pass
z += 1
print(final_list)
One way is this. There has to be at least one solution where you pick one number from each array and add them up to be greater than or equal to another.
Considering the fact that arrays might have random numbers in any order, first use this sort function to have them in decreasing order (largest number first, smallest number last) :
Arrays.sort(<array name>, Collections.reverseOrder());
Then pick the 1st element in the array :
v = A[0]
w = B[0]
x = C[0]
y = D[0]
z = E[0]
Then you can print them like this : v,w,x,y,z
Now your output will be :
7,9,4,7,15
Since it took the largest number of each array, it has to be equal to or greater than the given number, unless the number is greater than all of these combined in which case it is impossible.
Edit : I think I got the question wrong. If you want to know how many of the possible solutions there are, that is much easier.
First create a variable to store the possibilities
var total = 0
Use the rand function to get a random number. In your array say something like :
v=A[Math.random(0,A[].length)]
Do the same thing for all arrays, then add them up
var sum = v+w+x+y+z
Now you have an if statement to see if the sum is greater than or equal to the number given (lets say the value is stored in the variable "given")
if(sum >= given){
total+=1
}else{
<repeat the random function to restart the process and generate a new sum>
}
Finally, you need to repeat this multiple times as incase there are multiple solutions, the code will only find one and give you a false total.
To solve this, create a for loop and put all of this code inside it :
//create a variable outside to store the total number of elements in all the arrays
var elements = A[].length + B[].length + C[].length + D[].length + E[].length
for(var i = 0; i <= elements; i++){
<The code is inside here, except for "total" as otherwise the value will keep resetting>
}
The end result should look something like this :
var total = 0
var elements = A[].length + B[].length + C[].length + D[].length + E[].length
for(var i = 0; i <= elements; i++){
v=A[Math.random(0,A[].length)]
w=B[Math.random(0,B[].length)]
x=C[Math.random(0,C[].length)]
y=D[Math.random(0,D[].length)]
z=E[Math.random(0,E[].length)]
var sum = v+w+x+y+z
if(sum >= given){
total+=1
}else{
v=A[Math.random(0,A[].length)]
w=B[Math.random(0,B[].length)]
x=C[Math.random(0,C[].length)]
y=D[Math.random(0,D[].length)]
z=E[Math.random(0,E[].length)]
}
}
At the end just print the total once the entire cycle is over or just do
console.log(total)
This is just for reference and the code might not work, it probably has a bunch of bugs in it, this was just my 1st draft attempt at it. I have to test it out on my own but i hope you see where I'm coming from. Just look at the process, make your own amendments and this should work fine.
I have not deleted the first part of my answer even though it isn't the answer to this question just so that if you're having trouble in that part as well, where you select the highest possible number, it might help you
Good luck!
Let's say I have a set of elements S = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }
I would like to create combinations of 3 and group them in a way such that no number appears in more than one combination.
Here is an example:
{ {3, 7, 9}, {1, 2, 4}, {5, 6, 8} }
The order of the numbers in the groups does not matter, nor does the order of the groups in the entire example.
In short, I want every possible group combination from every possible combination in the original set, excluding the ones that have a number appearing in multiple groups.
My question: is this actually feasible in terms of run time and memory? My sample sizes could be somewhere around 30-50 numbers.
If so, what is the best way to create this algorithm? Would it be best to create all possible combinations, and choose the groups only if the number hasn't already appeared?
I'm writing this in Qt 5.6, which is a C++ based framework.
You can do this recursively, and avoid duplicates, if you keep the first element fixed in each recursion, and only make groups of 3 with the values in order, eg:
{1,2,3,4,5,6,7,8,9}
Put the lowest element in the first spot (a), and keep it there:
{a,b,c} = {1, *, *}
For the second spot (b), iterate over every value from the second-lowest to the second-highest:
{a,b,c} = {1, 2~8, *}
For the third spot (c), iterate over every value higher than the second value:
{1, 2~8, b+1~9}
Then recurse with the rest of the values.
{1,2,3} {4,5,6} {7,8,9}
{1,2,3} {4,5,7} {6,8,9}
{1,2,3} {4,5,8} {6,7,9}
{1,2,3} {4,5,9} {6,7,8}
{1,2,3} {4,6,7} {5,8,9}
{1,2,3} {4,6,8} {5,7,9}
{1,2,3} {4,6,9} {5,7,8}
{1,2,3} {4,7,8} {5,6,9}
{1,2,3} {4,7,9} {5,6,8}
{1,2,3} {4,8,9} {5,6,7}
{1,2,4} {3,5,6} {7,8,9}
...
{1,8,9} {2,6,7} {3,4,5}
Wen I say "in order", that doesn't have to be any specific order (numerical, alphabetical...), it can just be the original order of the input. You can avoid having to re-sort the input of each recursion if you make sure to pass the rest of the values on to the next recursion in the order you received them.
A run-through of the recursion:
Let's say you get the input {1,2,3,4,5,6,7,8,9}. As the first element in the group, you take the first element from the input, and for the other two elements, you iterate over the other values:
{1,2,3}
{1,2,4}
{1,2,5}
{1,2,6}
{1,2,7}
{1,2,8}
{1,2,9}
{1,3,4}
{1,3,5}
{1,3,6}
...
{1,8,9}
making sure the third element always comes after the second element, to avoid duplicates like:
{1,3,5} ⇆ {1,5,3}
Now, let's say that at a certain point, you've selected this as the first group:
{1,3,7}
You then pass the rest of the values onto the next recursion:
{2,4,5,6,8,9}
In this recursion, you apply the same rules as for the first group: take the first element as the first element in the group and keep it there, and iterate over the other values for the second and third element:
{2,4,5}
{2,4,6}
{2,4,8}
{2,4,9}
{2,5,6}
{2,5,8}
{2,5,9}
{2,6,7}
...
{2,8,9}
Now, let's say that at a certain point, you've selected this as the second group:
{2,5,6}
You then pass the rest of the values onto the next recursion:
{4,8,9}
And since this is the last group, there is only one possibility, and so this particular recursion would end in the combination:
{1,3,7} {2,5,6} {4,8,9}
As you see, you don't have to sort the values at any point, as long as you pass them onto the next recursion in the order you recevied them. So if you receive e.g.:
{q,w,e,r,t,y,u,i,o}
and you select from this the group:
{q,r,u}
then you should pass on:
{w,e,t,y,i,o}
Here's a JavaScript snippet which demonstrates the method; it returns a 3D array with combinations of groups of elements.
(The filter function creates a copy of the input array, with elements 0, i and j removed.)
function clone2D(array) {
var clone = [];
for (var i = 0; i < array.length; i++) clone.push(array[i].slice());
return clone;
}
function groupThree(input) {
var result = [], combination = [];
group(input, 0);
return result;
function group(input, step) {
combination[step] = [input[0]];
for (var i = 1; i < input.length - 1; i++) {
combination[step][1] = input[i];
for (var j = i + 1; j < input.length; j++) {
combination[step][2] = input[j];
if (input.length > 3) {
var rest = input.filter(function(elem, index) {
return index && index != i && index != j;
});
group(rest, step + 1);
}
else result.push(clone2D(combination));
}
}
}
}
var result = groupThree([1,2,3,4,5,6,7,8,9]);
for (var r in result) document.write(JSON.stringify(result[r]) + "<br>");
For n things taken 3 at a time, you could use 3 nested loops:
for(k = 0; k < n-2; k++){
for(j = k+1; j < n-1; j++){
for(i = j+1; i < n ; i++){
... S[k] ... S[j] ... S[i]
}
}
}
For a generic solution of n things taken k at a time, you could use an array of k counters.
I think You can solve it by using coin change problem with dynamic programming, just assume You are looking for change of 3 and every index in array is a coin value 1, then just output coins(values in Your array) that has been found.
Link: https://www.youtube.com/watch?v=18NVyOI_690
Here's one coding question I'm confused about.
Given a 2-D array [[1, 9], [2, 8], [2, 5], [3, 4], [6, 7], [6, 8]], each inner array represents an interval; and if we pile up these intervals, we'll see:
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8
2 3 4 5
3 4
6 7
6 7 8
Now there's a limit that the coverage should be <= 3 for each position; and obviously we could see for position 3, 4, 6, 7, the coverage is 4.
Then question is: maximally how many subsets of intervals can be chosen so that each interval could fit the <=3 limit? It's quite clear that for this case, we simply remove the longest interval [1, 9], so maximal subset number is 6 - 1 = 5.
What algorithm should I apply to such question? I guess it's variant question to interval scheduling?
Thanks
I hope I have understood the question right. This is the solution I could able to get with C#:
//test
int[][] grid = { new int[]{ 1, 9 }, new int[] { 2, 8 }, new int[] { 2, 5 }, new int[] { 3, 4 }, new int[] { 6, 7 }, new int[] { 6, 8 } };
SubsetFinder sf = new SubsetFinder(grid);
int t1 = sf.GetNumberOfIntervals(1);//6
int t2 = sf.GetNumberOfIntervals(2);//5
int t3 = sf.GetNumberOfIntervals(3);//5
int t4 = sf.GetNumberOfIntervals(4);//2
int t5 = sf.GetNumberOfIntervals(5);//0
class SubsetFinder
{
Dictionary<int, List<int>> dic;
int intervalCount;
public SubsetFinder(int[][] grid)
{
init(grid);
}
private void init(int[][] grid)
{
this.dic = new Dictionary<int, List<int>>();
this.intervalCount = grid.Length;
for (int r = 0; r < grid.Length; r++)
{
int[] row = grid[r];
if (row.Length != 2) throw new Exception("not grid");
int start = row[0];
int end = row[1];
if (end < start) throw new Exception("bad interval");
for (int i = start; i <= end; i++)
if (!dic.ContainsKey(i))
dic.Add(i, new List<int>(new int[] { r }));
else
dic[i].Add(r);
}
}
public int GetNumberOfIntervals(int coverageLimit)
{
HashSet<int> hsExclude = new HashSet<int>();
foreach (int key in dic.Keys)
{
List<int> lst = dic[key];
if (lst.Count < coverageLimit)
foreach (int i in lst)
hsExclude.Add(i);
}
return intervalCount - hsExclude.Count;
}
}
I think you can solve this problem using a sweep algorithm. Here's my approach:
The general idea is that instead of finding out the maximum number of intervals you can choose and still fit the limit, we will find the minimum number of intervals that must be deleted in order to make all the numbers fit the limit. Here's how we can do that:
First create a vector of triples, the first part is an integer, the second is a boolean, while the third part is an integer. The first part represents all the numbers from the input (both the start and end of intervals), the second part tells us whether the first part is the start or the end of an interval, while the third part represents the id of the interval.
Sort the created vector based on the first part, in case of a tie, the start should come before the end of some intervals.
In the example you provided the vector will be:
1,0 , 2,0 , 2,0 , 2,0 , 3,0 , 4,1 , 5,1 , 6.0 , 6.0 , 7,1 , 8,1 , 8,1 , 9,1
Now, iterate over the vector, while keeping a set of integers, which represents the intervals that are currently taken. The numbers inside the set represent the ends of the currently taken intervals. This set should be kept sorted in the increasing order.
While iterating over the vector, we might encounter one of the following 2 possibilities:
We are currently handling the start of an interval. In this case we simply add the end of this interval (which is identified by the third part id) to the set. If the size of the set is more than the limit, we must surely delete exactly one interval, but which interval is the best for deleting? Of course it's the interval with the biggest end because deleting this interval will not only help you reduce the number of taken intervals to fit the limit, but it will also be most helpful in the future since it lasts the most. Simply delete this interval from the set (the corresponding end will be last in the set, since the set is sorted in increasing order of the end)
We are currently handling the end of an interval, in this case check out the set. If it contains the specified end, just delete it, because the corresponding interval has come to its end. If the set doesn't contain an end that matches the one we are handling, simply just continue iterating to the next element, because this means we have already decided not to take the corresponding interval.
If you need to count the number of taken intervals, or even print them, it can be done easily. Whenever you handle the end of an interval, and you actually find this end at the set, this means that the corresponding interval is a taken one, and you may increment your answer by one, print it or keep it in some vector representing your answer.
The total complexity of my approach is : N Log(N), where N is the number of intervals given in the input.
My problem can be simplified as follows.
There're s bins, and within each bin there're k numbers.
A combination consists of one number from each bin, so in total there're k^s possible combinations.
The score of a combination is the sum of s numbers it contains.
How can I find all the combinations with score less than some value r?
Right now what I'm doing is,
1) sort the numbers in each bin.
2) start with a priority queue that only contains the combination of the smallest number from each bin.
3) pop a combination from the queue, add s children of that combination to to queue. (a child of a combination is made of replacing one number of the combination to the next larger number in the same bin, so there're s children of a combination.)
4) repeat 3) till the combination popped is larger than r.
Suppose we find n combinations smaller than r, the time complexity of this algorithm is then O(nlog(s-1)n + sklogk).
Of course this algorithm is not optimal. For example instead of starting with the smallest combination, we can start with a known lower bound. And I sort of have a feeling that dynamic programming can be applied here too, but I didn't figure out how to do it.
Any suggestions are welcome, thanks.
After having sorted the bins, you could use a recursive algorithm, that extends a partial selection with an element from the next bin until the selection is complete (or overruns the sum limit). When complete, it is added to the result. Through backtracking all the valid selections get added to the result.
Here is some pseudo code. The last argument is both input and output:
function combinations(int[][] bins, int r, int[] selection, int[][] result):
if r < 0 then:
return
if selection.length >= bins.length then:
result.add(selection)
return
bin = bins[selection.length]
for (i = 0; i < bin.length; i++):
# Concatenate the i-th value from the bin to a new selection array
combinations(bins, r - bin[i], selection + bin[i], result)
Here is an implementation in JavaScript:
function sortBins(bins) {
for (bin of bins) {
bin.sort(function (a,b) { return a-b; });
}
}
function combinations(bins, r, selection, result) {
if (r < 0) return result; // nothing added to result
if (selection.length >= bins.length) return result.concat([selection]);
var bin = bins[selection.length];
for (var i = 0; i < bin.length; i++)
result = combinations(bins, r - bin[i], selection.concat([bin[i]]), result);
return result;
}
// Test data:
var r = 13;
var bins = [
[5, 2, 3],
[9, 4, 1],
[6, 5, 7]
];
// Get solution:
sortBins(bins);
var result = combinations(bins, r, [], []);
// Output results:
console.log(result);
Actually, this question can be generalized as below:
Find all possible combinations from a given set of elements, which meets
a certain criteria.
So, any good algorithms?
There are only 16 possibilities (and one of those is to add together "none of them", which ain't gonna give you 24), so the old-fashioned "brute force" algorithm looks pretty good to me:
for (unsigned int choice = 1; choice < 16; ++choice) {
int sum = 0;
if (choice & 1) sum += elements[0];
if (choice & 2) sum += elements[1];
if (choice & 4) sum += elements[2];
if (choice & 8) sum += elements[3];
if (sum == 24) {
// we have a winner
}
}
In the completely general form of your problem, the only way to tell whether a combination meets "certain criteria" is to evaluate those criteria for every single combination. Given more information about the criteria, maybe you could work out some ways to avoid testing every combination and build an algorithm accordingly, but not without those details. So again, brute force is king.
There are two interesting explanations about the sum problem, both in Wikipedia and MathWorld.
In the case of the first question you asked, the first answer is good for a limited number of elements. You should realize that the reason Mr. Jessop used 16 as the boundary for his loop is because this is 2^4, where 4 is the number of elements in your set. If you had 100 elements, the loop limit would become 2^100 and your algorithm would literally take forever to finish.
In the case of a bounded sum, you should consider a depth first search, because when the sum of elements exceeds the sum you are looking for, you can prune your branch and backtrack.
In the case of the generic question, finding the subset of elements that satisfy certain criteria, this is known as the Knapsack problem, which is known to be NP-Complete. Given that, there is no algorithm that will solve it in less than exponential time.
Nevertheless, there are several heuristics that bring good results to the table, including (but not limited to) genetic algorithms (one I personally like, for I wrote a book on them) and dynamic programming. A simple search in Google will show many scientific papers that describe different solutions for this problem.
Find all possible combinations from a given set of elements, which
meets a certain criteria
If i understood you right, this code will helpful for you:
>>> from itertools import combinations as combi
>>> combi.__doc__
'combinations(iterable, r) --> combinations object\n\nReturn successive r-length
combinations of elements in the iterable.\n\ncombinations(range(4), 3) --> (0,1
,2), (0,1,3), (0,2,3), (1,2,3)'
>>> set = range(4)
>>> set
[0, 1, 2, 3]
>>> criteria = range(3)
>>> criteria
[0, 1, 2]
>>> for tuple in list(combi(set, len(criteria))):
... if cmp(list(tuple), criteria) == 0:
... print 'criteria exists in tuple: ', tuple
...
criteria exists in tuple: (0, 1, 2)
>>> list(combi(set, len(criteria)))
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
Generally for a problem as this you have to try all posebilities, the thing you should do have the code abort the building of combiantion if you know it will not satesfie the criteria (if you criteria is that you do not have more then two blue balls, then you have to abort calculation that has more then two). Backtracing
def perm(set,permutation):
if lenght(set) == lenght(permutation):
print permutation
else:
for element in set:
if permutation.add(element) == criteria:
perm(sett,permutation)
else:
permutation.pop() //remove the element added in the if
The set of input numbers matters, as you can tell as soon as you allow e.g. negative numbers, imaginary numbers, rational numbers etc in your start set. You could also restrict to e.g. all even numbers, all odd number inputs etc.
That means that it's hard to build something deductive. You need brute force, a.k.a. try every combination etc.
In this particular problem you could build an algoritm that recurses - e.g. find every combination of 3 Int ( 1,22) that add up to 23, then add 1, every combination that add to 22 and add 2 etc. Which can again be broken into every combination of 2 that add up to 21 etc. You need to decide if you can count same number twice.
Once you have that you have a recursive function to call -
combinations( 24 , 4 ) = combinations( 23, 3 ) + combinations( 22, 3 ) + ... combinations( 4, 3 );
combinations( 23 , 3 ) = combinations( 22, 2 ) + ... combinations( 3, 2 );
etc
This works well except you have to be careful around repeating numbers in the recursion.
private int[][] work()
{
const int target = 24;
List<int[]> combos = new List<int[]>();
for(int i = 0; i < 9; i++)
for(int x = 0; x < 9; x++)
for(int y = 0; y < 9; y++)
for (int z = 0; z < 9; z++)
{
int res = x + y + z + i;
if (res == target)
{
combos.Add(new int[] { x, y, z, i });
}
}
return combos.ToArray();
}
It works instantly, but there probably are better methods rather than 'guess and check'. All I am doing is looping through every possibility, adding them all together, and seeing if it comes out to the target value.
If i understand your question correctly, what you are asking for is called "Permutations" or the number (N) of possible ways to arrange (X) numbers taken from a set of (Y) numbers.
N = Y! / (Y - X)!
I don't know if this will help, but this is a solution I came up with for an assignment on permutations.
You have an input of : 123 (string) using the substr functions
1) put each number of the input into an array
array[N1,N2,N3,...]
2)Create a swap function
function swap(Number A, Number B)
{
temp = Number B
Number B = Number A
Number A = temp
}
3)This algorithm uses the swap function to move the numbers around until all permutations are done.
original_string= '123'
temp_string=''
While( temp_string != original_string)
{
swap(array element[i], array element[i+1])
if (i == 1)
i == 0
temp_string = array.toString
i++
}
Hopefully you can follow my pseudo code, but this works at least for 3 digit permutations
(n X n )
built up a square matrix of nxn
and print all together its corresponding crossed values
e.g.
1 2 3 4
1 11 12 13 14
2 .. .. .. ..
3 ..
4 .. ..