Numbers distribution - c#

I have a problem with numbers distribution to perfectly fit given container. My numbers are:
int[] number = {50, 40, 30, 30, 25, 25};
I want to find a best combo which will be nearest to 100, and when no more options available start another container of 100. Simple solution like sorting and adding from max to min won't work, because:
int[] firstContainer = { 50, 40 }; //10 unused
int[] secontContainer = { 30, 30, 25 }; //15 unused
int[] thirdContainer = { 25 }; //75 unused
The result what I'm looking for is:
int[] firstContainer = { 50, 25, 25 }; //0 unused
int[] secontContainer = { 40, 30, 30 }; //0 unused
Is there any kind soul willing to help me solve the problem?

Here is one solution - it can be optimized and improved, but now you have a starting point. Starting point is to create all combinations of your initial array and then get the sum
static void Main(string[] args)
{
int[] number = { 50, 40, 30, 30, 25, 25 };
foreach (var kvp in Exercise(number, 100))
{
Console.WriteLine("Solution " + kvp.Key);
foreach (var sol in kvp.Value)
{
Console.Write(sol + " ");
}
Console.WriteLine();
}
}
private static Dictionary<int, List<int>> Exercise(int[] number, int sum)
{
Dictionary<int, List<int>> results = new Dictionary<int, List<int>>();
int counter = 0;
var numberOfCombinations = Math.Pow(2, number.Count());
for (int i = 0; i < numberOfCombinations; i++)
{
//convert an int to binary and pad it with 0, so I will get an array which is the same size of the input[] array. ie for example 00000, then 00001, .... 11111
var temp = Convert.ToString(i, 2).PadLeft(number.Count(), '0').ToArray();
List<int> positions = new List<int>();
int total = 0;
for (int k = 0; k < temp.Length; k++)
{
if (temp[k] == '1')
{
total += number[k];
positions.Add(number[k]);
}
}
if (total == sum)
{
results.Add(counter, positions);
counter++;
}
}
return results;
}

My solution is based on generating random and feasible answers, at the end we can find best answer :
static void Main(string[] args)
{
int[] number = { 50, 40, 30, 30, 25, 25 };
int bound = 100;
var numbers = new List<dynamic>();
Random rnd = new Random();
var ans_collection = new List<List<List<int>>>();
//number of random answers , best answer depends on i so you can't be sure this algorithm always finds optimal answer choose i big enough...
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < number.Length; j++)
{
numbers.Add(new { num = number[j], seen = false });
}
var ans = new List<List<int>>();
var container = new List<int>();
var distSum = 0;
//while loop generates a distribution
while (numbers.Where(x => !x.seen).Count() > 0)
{
var chosen = numbers.OrderBy(x => rnd.NextDouble()).Where(x => !x.seen && distSum + x.num <= bound).FirstOrDefault();
if (numbers.Where(x => !x.seen && distSum + x.num <= bound).Count() > 0)
{
container.Add(chosen.num);
distSum += chosen.num;
numbers.Add(new { num = chosen.num, seen = true });
numbers.Remove(chosen);
if (numbers.Where(x => !x.seen && distSum + x.num <= bound).Count() == 0)
{
ans.Add(new List<int>(container));
container = new List<int>();
distSum = 0;
}
}
else
{
ans.Add(new List<int>(container));
container = new List<int>();
distSum = 0;
}
}
ans_collection.Add(new List<List<int>>(ans));
}
//find best answer based on sum of *unused* amounts
var min = ans_collection.Min(ans => ans.Sum(dis => (bound - dis.Sum())));
var best = ans_collection.Where(ans => ans.Sum(dis => (bound - dis.Sum())) == min).FirstOrDefault();
best.ForEach(x => Console.WriteLine(string.Join(",", x.Select(Y => Y.ToString()))));
}

Related

calculate combination in C# without recursive function

i would like to calculate all the combination possible, but i don't want to use recursive function just some simple code in C# ?
Here is example :
col1 col2 col3
valueinf= 5 6 7
valuesup= 10 20 30
i want this for result:
res1 = 5+6+7
res2 = 5+6+30
res3 = 5+20+7
res4 = 5+20+30
res5 = 10+6+7
res6 = 10+6+30
res7 = 10+20+7
res8 = 10+20+30
the number of colonne is variable but i wil allways have 2 lines one inferior and one superior.
I don't know how to begin the algorithm. Some help will be gratefull just to begin
Well, will-nilly you have to loop:
using System.Linq;
...
private static IEnumerable<int> Sums(IEnumerable<int[]> columns) {
if (columns is null)
throw new ArgumentNullException(nameof(columns));
int[][] data = columns.ToArray();
int[] pos = new int[data.Length];
do {
yield return Enumerable.Range(0, data.Length).Sum(i => data[i][pos[i]]);
for (int i = pos.Length - 1; i >= 0; --i)
if (pos[i] == data[i].Length - 1)
pos[i] = 0;
else {
pos[i] += 1;
break;
}
}
while (!pos.All(p => p == 0));
}
The very same idea if you want to print formulae:
private static IEnumerable<string> Formulae(IEnumerable<int[]> columns) {
if (columns is null)
throw new ArgumentNullException(nameof(columns));
int[][] data = columns.ToArray();
int[] pos = new int[data.Length];
do {
yield return string.Join("+", Enumerable
.Range(0, data.Length).Select(i => data[i][pos[i]]));
for (int i = pos.Length - 1; i >= 0; --i)
if (pos[i] == data[i].Length - 1)
pos[i] = 0;
else {
pos[i] += 1;
break;
}
}
while (!pos.All(p => p == 0));
}
Demo:
List<int[]> columns = new List<int[]>() {
new int[] {5, 10},
new int[] {6, 20},
new int[] {7, 30},
};
var sums = Sums(columns);
var formulae = Formulae(columns);
Console.WriteLine(string.Join(Environment.NewLine, sums
.Select((v, i) => $"res{i+1} = {v}")));
Console.WriteLine();
Console.WriteLine(string.Join(Environment.NewLine, formulae
.Select((v, i) => $"res{i+1} = {v}")));
Outcome:
res1 = 18
res2 = 41
res3 = 32
res4 = 55
res5 = 23
res6 = 46
res7 = 37
res8 = 60
res1 = 5+6+7
res2 = 5+6+30
res3 = 5+20+7
res4 = 5+20+30
res5 = 10+6+7
res6 = 10+6+30
res7 = 10+20+7
res8 = 10+20+30
Edit: To find the best fit you can exploit the very same principle:
private static (int[] pos, int diff, string formula) BestFit(int target, IEnumerable<int[]> columns) {
if (columns is null)
throw new ArgumentNullException(nameof(columns));
int[][] data = columns.ToArray();
int[] pos = new int[data.Length];
int bestDiff = -1;
int[] bestPos = null;
do {
int diff = Math.Abs(target - Enumerable.Range(0, data.Length).Sum(i => data[i][pos[i]]));
if (diff < bestDiff || bestPos == null) {
bestPos = pos.ToArray();
bestDiff = diff;
}
for (int i = pos.Length - 1; i >= 0; --i)
if (pos[i] == data[i].Length - 1)
pos[i] = 0;
else {
pos[i] += 1;
break;
}
}
while (!pos.All(p => p == 0));
return (
bestPos,
bestDiff,
string.Join("+", Enumerable.Range(0, data.Length).Select(i => data[i][bestPos[i]]))
);
}
Demo:
int[][] data = new int[][] {
new int[] {5, 10},
new int[] {6, 20},
new int[] {7, 30},
};
var fit = BestFit(20, data);
Console.Write($"delta = {fit.diff}; formula = {fit.formula}");
Outcome:
delta = 2; formula = 5+6+7

C#, Trying to pull prime numbers from generated array all I get is 0

The program will generate a sequence of randomly chosen numbers between 1 – 100. The sequence will consist of 20 elements.
Your program should display the sequence once it is generated.
Then, it will display all prime numbers within this sequence.
The code so far:
class Program
{
int[] rnum = new int[100];
int[] selecting = new int[20];
static void Main(string[] args)
{
Program myProgram = new Program();
myProgram.Numbers();
myProgram.PrimeN();
Console.ReadLine();
}
public void Numbers()
{
int[] rnum = new int[100];
// Filling the array with values 1 to 100:
for (int i = 0; i < rnum.Length; i++)
{
rnum[i] = i + 1;
}
// Shuffling the elements of the array:
Random rnd = new Random();
for (int i = 0; i < rnum.Length; i++)
{
int j = rnd.Next(i, rnum.Length);
int temp = rnum[i];
rnum[i] = rnum[j];
rnum[j] = temp;
}
// Selecting and presenting 20 numbers:
int[] selecting = new int[20];
for (int i = 0; i < 20; i++)
selecting[i] = rnum[i];
selecting.ToList().ForEach(i => Console.Write(i.ToString() + ", "));
Console.WriteLine();
}
public void PrimeN()
{
List<int> primeNumbers = new List<int>();
for (int i = 0; i < selecting.Length; i++)
{
if (IsPrime(selecting[i]))
{
primeNumbers.Add(selecting[i]);
}
}
Console.Write("Non-Prime Numbers:");
for (int i = 0; i < primeNumbers.Count; i++)
{
Console.Write(primeNumbers[i] + " ");
}
}
bool IsPrime(int number)
{
for (int i = 2; i < Math.Sqrt(number); i++)
{
if (number % i == 0) return false;
}
return true;
}
}
}
You created local variable called selecting inside Numbers() function. Scope of this local variable is within Numbers() function.
When you are trying to read same variable in PrimeN(), it is referring to the globally defined selecting variable.
As there is nothing stored in global selecting variable you are getting 0 as result in primeNumbers array.
To Solve this issue, do not create local variable called selecting inside Numbers() function, use globally defined variable i.e. selecting defined at class level
...
public void Numbers()
{
...
// Selecting and presenting 20 numbers:
//COMMENT BELOW LINE
//int[] selecting = new int[20];
for (int i = 0; i < 20; i++)
selecting[i] = rnum[i]; //This will refer member which is defined globally
selecting.ToList().ForEach(i => Console.Write(i.ToString() + ", "));
Console.WriteLine();
}
The first problem I see, is you are creating local variables, instead of using the instance members you have declared, after your method runs, nothing gets changed... it all happened locally in the method.
Comment out the below lines, you have already declared them
public static void Numbers(int size)
{
//int[] rnum = new int[size];
...
//int[] selecting = new int[20];
Though it could all be reduced to
private static readonly Random _r = new Random();
static void Main(string[] args)
{
var numbers = Generate(100);
var selected = numbers.Take(20).ToArray();
Console.WriteLine("Selected : " + string.Join(", ", selected));
Console.Write("Primes : " + string.Join(",", selected.Where(IsPrime)));
Console.ReadLine();
}
public static int[] Generate(int size)
{
var numbers = Enumerable.Range(1, 100).ToArray();
// Shuffling the elements of the array:
for (var i = 0; i < numbers.Length; i++)
{
var j = _r.Next(i, numbers.Length);
var temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}
return numbers;
}
private static bool IsPrime(int number)
{
for (var i = 2; i < Math.Sqrt(number); i++)
if (number % i == 0) return false;
return true;
}
Output
Selected : 92, 79, 1, 44, 83, 48, 70, 49, 80, 19, 27, 65, 50, 40, 20, 10, 68, 25, 9, 28
Primes : 79,1,83,49,19,25,9

Remove minimum amount of chess knights so no remaining knight threatens another knight

I have trouble coming up with an algorithm for Knight Game task.
The description of the task is:
The knight game is played on a board with dimensions N x N and a lot of chess knights 0 <= K <= N².
I receive a board (char matrix) with 'K' for knights and '0' for empty cells. My task is to remove a minimum of the knights, so there will be no knights left that can attack another knight. On the first line, I receive the N size of the board. On the next N lines I receive strings with Ks and 0s.
This is what I devised so far:
public class SolutionTwo
{
public static void Main()
{
var size = int.Parse(Console.ReadLine());
var board = new char[size][];
PrepareBoard(board);
var knights = new List<Knight>();
for (int x = 0; x < board.Length; x++)
{
for (int y = 0; y < board[x].Length; y++)
{
if (board[x][y] == 'K')
{
knights.Add(new Knight()
{
X = x,
Y = y,
KnightAttacks = GetKnightAttacks(x, y, board)
});
}
}
}
var count = 0;
foreach (var knight in knights.OrderByDescending(k => k.KnightAttacks.Count()))
{
if (!IsReaminingHits(board))
{
break;
}
board[knight.X][knight.Y] = '0';
count++;
foreach (var subK in knight.KnightAttacks)
{
var c = knights.Single(k => k.X == subK.Item1 && k.Y == subK.Item2);
c.KnightAttacks.Remove(new Tuple<int, int>(knight.X, knight.Y));
}
// for test purposes
//Console.WriteLine($"Kn: [{knight.X} {knight.Y}] - he attacks: {string.Join(" ", knight.KnightAttacks)} {knight.KnightAttacks.Count()}");
}
Console.WriteLine(count);
}
private static bool IsReaminingHits(char[][] board)
{
for (int i = 0; i < board.Length; i++)
{
for (int j = 0; j < board[i].Length; j++)
{
if (board[i][j] == 'K')
{
if (GetKnightAttacks(i, j, board).Count > 0)
{
return true;
}
}
}
}
return false;
}
private static void PrepareBoard(char[][] board)
{
for (int i = 0; i < board.Length; i++)
{
board[i] = Console.ReadLine()
.ToCharArray();
}
}
private static List<Tuple<int, int>> GetKnightAttacks(int x, int y, char[][] board)
{
var deltas = new int[8][]
{
new int[] {-2, -1},
new int[] {-2, +1},
new int[] {+2, -1},
new int[] {+2, +1},
new int[] {-1, -2},
new int[] {-1, +2},
new int[] {+1, -2},
new int[] {+1, +2}
};
var xCandidate = 0;
var yCandidate = 0;
var list = new List<Tuple<int, int>>();
for (int i = 0; i < 8; i++)
{
xCandidate = x + deltas[i][0];
yCandidate = y + deltas[i][1];
if (0 <= xCandidate && xCandidate < board.Length
&& 0 <= yCandidate && yCandidate < board[0].Length
&& board[xCandidate][yCandidate] == 'K')
{
list.Add(new Tuple<int, int>(xCandidate, yCandidate));
}
}
return list;
}
}
public class Knight
{
public int X { get; set; }
public int Y { get; set; }
public List<Tuple<int, int>> KnightAttacks { get; set; } = new List<Tuple<int, int>>();
}
Example #1:
Input:
5
0K0K0
K000K
00K00
K000K
0K0K0
Expected result: 1
Example #2:
Input:
8
0K0KKK00
0K00KKKK
00K0000K
KKKKKK0K
K0K0000K
KK00000K
00K0K000
000K00KK
Expected result: 12
The algorithm is flawed, as can be seen more easily on this smaller board:
4
000K
0K00
00K0
K000
The solution here should be 2; but the algorithm returns 3. The reason for this is that the algorithm removes the first knight with the most attacks; assuming that this removal is part of the correct answer; however, there may be multiple knights with that number of attacks, and the first is not necessarily the best choice.
Also knights.OrderByDescending(k => k.KnightAttacks.Count()) doesn't do what you want it to do, even if you add knight.KnightAttacks.Clear(); inside the loop, since it has to evaluate all the values in order to enumerate them; but of course those numbers will vary as you start removing knights.
The correct algorithm is going to need to try all of the alternatives with the same number of attacks, to work out which is best. I can also come up with scenarios where the knight-with-the-most-attacks is not be the best choice. For example:
7
K00000K
00K0K00
KK000KK
0K0K0K0
0000000
0000000
0000000
So using the following replacement for the code beginning var count=0; improves the algorithm a little (e.g. it gets the correct answer of 2 for my small example, and 12 for "Example #2"); but isn't the full solution:
var count = 0;
while (knights.Any(k => k.KnightAttacks.Count > 0))
{
var knight = knights.OrderByDescending(k => k.KnightAttacks.Count).First();
// for test purposes
//Console.WriteLine($"Kn: [{knight.X} {knight.Y}] - he attacks: {string.Join(" ", knight.KnightAttacks)} {knight.KnightAttacks.Count()}");
board[knight.X][knight.Y] = '0';
count++;
foreach (var subK in knight.KnightAttacks)
{
var c = knights.Single(k => k.X == subK.Item1 && k.Y == subK.Item2);
c.KnightAttacks.Remove(new Tuple<int, int>(knight.X, knight.Y));
}
knight.KnightAttacks.Clear();
}

Forcing one more iteration of loop?

int iterationMax = 1;
double actualMax = 0;
int A = 3;
List<double> tmp = new List<double> { 400, 0, -300, 400, 600 ,300, 400,
1200, 900, 400, 1200, 1500};
List<double> listMax = new List<double>();
for (int i = 0; i < tmp.Count; i++)
{
if (iterationMax < A) // A == 3
{
if (tmp[i] > actualMax)
{
actualMax = tmp[i];
}
iterationMax++;
}
else
{
listMax.Add(actualMax);
actualMax = 0;
iterationMax = 1;
}
}
Console.WriteLine("\nMaxs: ");
foreach (double max in listMax)
{
Console.Write(max + ", ");
}
List tmp holds = { 400,0,-300|400,600,300|400,1200,900|400,1200,1500},
Produce 400, 600, 1200, 1200,
Should be 400, 600, 1200, 1500. I don't know how to enter else statement to add 1500 to list.
I just want to get max from every 3 elements.
When one needs to perform manipulations on collection it is many times nicer to use Linq.
Use GroupBy in the index/3 and as it is an int each 3 following items will have a different key. Then for each group select the maximum value:
var items = new int[] { 400, 0, -300, 400, 600, 300, 400, 1200, 900 };
var results = items.Select((item, index) => new { item, index })
.GroupBy(item => item.index / 3)
.Select(group => group.Max(item => item.item));
//400, 600, 1200
A quick fix for your code would be:
var A = 3;
int iterationMax = 0;
double actualMax = 0;
List<double> tmp = new List<double> {400,0,-300,400,600,300,400,1200,900,400,1200,1500};
List<double> listMax = new List<double>();
for (int i = 0; i < tmp.Count; i++)
{
if (iterationMax < A) // A == 3
{
if (tmp[i] > actualMax)
{
actualMax = tmp[i];
}
iterationMax++;
}
if (iterationMax == A)
{
listMax.Add(actualMax);
actualMax = 0;
iterationMax = 0;
}
}
Console.WriteLine("\nMaxs: ");
foreach (double max in listMax)
{
Console.Write(max + ", ");
}
As others have said, start iterationMax from 0 and turn that else into an if (iterationMax == A).
Setting iterationMax to 0 in initialization and under else should solve your issue.
Currently your if structure will only check the first two out of three elements. Since 1500 is element #3, it will not be checked.
The problem is, when iterationMax reaches 3, you don't do anything with the value in temp, that loop is lost.
for (int i = 0; i < tmp.Count; i++)
{
if (tmp[i] > actualMax)
{
actualMax = tmp[i];
}
iterationMax++;
if (iterationMax > A)
{
listMax.Add(actualMax);
actualMax = 0;
iterationMax = 1;
}
}

Algorithm for finding a group of numbers in a list that equal a target

So here is what I'm trying to do. I have a list of integers:
List<int> myList = new List<int>() {5,7,12,8,7};
And I also got a target:
int target = 20;
What I'm trying to do is find a way to create a new list of integer that when added together equal my target. So if my target is 20, I need a list like this:
{ 12, 8 }
If my target is 26, then I'll have this:
{ 7, 12, 7 }
Each number can only be used one time (7 is used twice because its in the list twice). If there is no solution, it should return an empty list. Anyone have any idea how I can do something like this?
That's a statistical problem. You want to find all possible combinations with a matching sum. I can recommend this project which is also worth reading:
http://www.codeproject.com/Articles/26050/Permutations-Combinations-and-Variations-using-C-G
Then it's easy and efficient:
List<int> myList = new List<int>() { 5, 7, 12, 8, 7 };
var allMatchingCombos = new List<IList<int>>();
for (int lowerIndex = 1; lowerIndex < myList.Count; lowerIndex++)
{
IEnumerable<IList<int>> matchingCombos = new Combinations<int>(myList, lowerIndex, GenerateOption.WithoutRepetition)
.Where(c => c.Sum() == 20);
allMatchingCombos.AddRange(matchingCombos);
}
foreach(var matchingCombo in allMatchingCombos)
Console.WriteLine(string.Join(",", matchingCombo));
Output:
12,8
5,7,8
5,8,7
Using recursion. Note that this solution will favor solutions that can be acquired by using the first items from the list. So for a target of 20, you won’t get 12+8 as the solution but 5+7+8.
List<int> findSum(List<int> numbers, int target, int index = 0)
{
// loop through all numbers starting from the index
for (var i = index; i < numbers.Count; i++)
{
int remainder = target - numbers[i];
// if the current number is too big for the target, skip
if (remainder < 0)
continue;
// if the current number is a solution, return a list with it
else if (remainder == 0)
return new List<int>() { numbers[i] };
else
{
// otherwise try to find a sum for the remainder later in the list
var s = findSum(numbers, remainder, i + 1);
// if no number was returned, we could’t find a solution, so skip
if (s.Count == 0)
continue;
// otherwise we found a solution, so add our current number to it
// and return the result
s.Insert(0, numbers[i]);
return s;
}
}
// if we end up here, we checked all the numbers in the list and
// found no solution
return new List<int>();
}
void Main()
{
List<int> myList = new List<int>() { 5, 7, 12, 8, 7 };
Console.WriteLine(findSum(myList, 12)); // 5, 7
Console.WriteLine(findSum(myList, 20)); // 5, 7, 8
Console.WriteLine(findSum(myList, 31)); // 5, 7, 12, 7
}
You can find all the solutions given below here: https://github.com/Mr-Zoidberg/Find-Possible-Combinations
1. Using recursion
static void Main(string[] args)
{
const int target = 20;
var numbers = new List<int> { 1, 2, 5, 8, 12, 14, 9 };
Console.WriteLine($"Number of Combinations: {SumCounter(numbers, target)}");
Console.ReadKey();
}
private static int SumCounter(IReadOnlyList<int> numbers, int target)
{
var result = 0;
RecursiveCounter(numbers, target, new List<int>(), ref result);
return result;
}
private static void RecursiveCounter(IReadOnlyList<int> numbers, int target, List<int> partial, ref int result)
{
var sum = partial.Sum();
if (sum == target)
{
result++;
Console.WriteLine(string.Join(" + ", partial.ToArray()) + " = " + target);
}
if (sum >= target) return;
for (var i = 0; i < numbers.Count; i++)
{
var remaining = new List<int>();
for (var j = i + 1; j < numbers.Count; j++) remaining.Add(numbers[j]);
var partRec = new List<int>(partial) { numbers[i] };
RecursiveCounter(remaining, target, partRec, ref result);
}
}
2. Get subsets using Linq
static void Main(string[] args)
{
const int target = 20;
var numbers = new int[] { 1, 2, 5, 8, 12, 14, 9 };
var matches = numbers.GetSubsets().Where(s => s.Sum() == target).ToArray();
foreach (var match in matches) Console.WriteLine(match.Select(m => m.ToString()).Aggregate((a, n) => $"{a} + {n}") + $" = {target}");
Console.WriteLine($"Number of Combinations: {matches.Length}");
Console.ReadKey();
}
}
public static class Extension
{
public static IEnumerable<IEnumerable<T>> GetSubsets<T>(this IEnumerable<T> collection)
{
if (!collection.Any()) return Enumerable.Repeat(Enumerable.Empty<T>(), 1);
var element = collection.Take(1);
var ignoreFirstSubsets = GetSubsets(collection.Skip(1));
var subsets = ignoreFirstSubsets.Select(set => element.Concat(set));
return subsets.Concat(ignoreFirstSubsets);
}
3. Another recursive method...
static void Main(string[] args)
{
const int target = 20;
var numbers = new [] { 1, 2, 5, 8, 12, 14, 9 };
var result = GetSubsets(numbers, target, "");
foreach (var subset in result) Console.WriteLine($"{subset} = {target}");
Console.WriteLine($"Number of Combinations: {result.Count()}");
Console.ReadLine();
}
public static IEnumerable<string> GetSubsets(int[] set, int sum, string values)
{
for (var i = 0; i < set.Length; i++)
{
var left = sum - set[i];
var vals = values != "" ? $"{set[i]} + {values}" : $"{set[i]}";
if (left == 0) yield return vals;
else
{
int[] possible = set.Take(i).Where(n => n <= sum).ToArray();
if (possible.Length <= 0) continue;
foreach (string s in GetSubsets(possible, left, vals)) yield return s;
}
}
}
4. Using binary search. Linear time.
static void Main(string[] args)
{
const int target = 20;
var numbers = new [] { 1, 2, 5, 8, 12, 14, 9 };
var subsets = GetSubsets(numbers, target);
foreach (var s in subsets) Console.WriteLine($"{s} = {target}");
Console.WriteLine($"Number of Combinations: {subsets.Count()}");
Console.ReadKey();
}
private static IEnumerable<string> GetSubsets(int[] array, int target)
{
Array.Sort((Array)array);
List<string> result = new List<string>();
for (int i = array.Length-1; i >= 0; i--)
{
var eq = $"{array[i]}";
var sum = array[i];
var toAdd = 0;
while (sum != target)
{
var mid = Array.BinarySearch(array, 0, sum <= target / 2 && sum != array[i] ? array.Length - 1 : i, target - sum);
mid = mid < 0 ? ~mid - 1 : mid;
if (mid == i || mid < 0 || toAdd == array[mid] ) break;
toAdd = array[mid];
sum += array[mid];
eq += $" + {array[mid]}";
if (sum == target) result.Add(eq);
}
}
return result;
}
This implementation of mine in C# will return all combinations(including repetitive use of same number) that equals a given number.
string r;
List<int> l = new List<int>();
void u(int w, int s, int K, int[] A) {
// If a unique combination is found
if (s == K) {
r += "(" + String.Join(" ", l) + ")";
return;
}
// For all other combinations
for (int i=w; i<A.Length; i++){
// Check if the sum exceeds K
int x = A[i];
if (s + x <= K){
l.Add(x);
u(i, s + x, K,A);
l.Remove(x);
}
}
}
string combinationSum(int[] a, int s) {
r = "";
u(0, 0, s, a.Distinct().OrderBy(x=>x).ToArray());
return r.Any() ? r : "Empty";
}
for a: [2, 3, 5, 9] and s = 9
the result will be :
"(2 2 2 3)(2 2 5)(3 3 3)(9)"

Categories