我有一个练习有问题。任务是找到数组中所有总和等于N的子集并打印它们。此外,我需要找到所有独特的子集,这是问题所在。我使用Gray方法查找所有组合,但其中一些是重复的。这是我的代码:
int matchSum = int.Parse(Console.ReadLine());
int[] numbers = Console.ReadLine().Split().Select(int.Parse).ToArray();
int combinations = (int) Math.Pow(2, numbers.Length);
List<int> currentSequence = new List<int>();
bool foundMatch = false;
for (int i = 1; i < combinations; i++)
{
for (int bit = 0; bit < Convert.ToString(i,2).Length; bit++)
{
int mask = (i >> bit) & 1;
if (mask == 1)
{
currentSequence.Add(numbers[numbers.Length-bit-1]);
}
}
if (currentSequence.Sum() == matchSum)
{
Console.WriteLine("{0} = {1}", string.Join(" + ", currentSequence), matchSum);
foundMatch = true;
}
currentSequence.Clear();
}
if (!foundMatch)
{
Console.WriteLine("No matching subsets.");
}
祝你好运!
答案 0 :(得分:0)
这是一个回溯算法实现。它的工作原理是首先对输入集进行排序,然后生成子集并检查总和。有3个关键点。首先,算法始终保持当前的总和,因此不需要在每一步完全计算它。其次,如果当前总和大于目标总和,则提前停止。最后,为了生成唯一的子集,后退步骤会跳过等于前一个序列的最后一个数字的数字。希望有所帮助。
using System;
using System.Collections.Generic;
using System.Linq;
namespace Samples
{
class Sample
{
static void Main(string[] args)
{
int matchSum = 20; // int.Parse(Console.ReadLine());
int[] numbers = { 5, 1, 3, 2, 5, 1, 8, 7, 4 }; // Console.ReadLine().Split().Select(int.Parse).ToArray();
Array.Sort(numbers);
var stack = new Stack<int>();
int matchCount = 0, currentSum = 0, nextPos = 0;
while (true)
{
// Next
for (int nextSum; nextPos < numbers.Length; currentSum = nextSum, nextPos++)
{
nextSum = currentSum + numbers[nextPos];
if (nextSum > matchSum) break;
stack.Push(nextPos);
if (nextSum < matchSum) continue;
matchCount++;
Console.WriteLine("{0} = {1}", matchSum, string.Join(" + ", stack.Reverse().Select(pos => numbers[pos])));
stack.Pop();
break;
}
// Back
if (stack.Count == 0) break;
var lastPos = stack.Pop();
var lastNumber = numbers[lastPos];
currentSum -= lastNumber;
nextPos = lastPos + 1;
while (nextPos < numbers.Length && numbers[nextPos] == lastNumber)
nextPos++;
}
if (matchCount == 0)
{
Console.WriteLine("No matching subsets.");
}
Console.ReadLine();
}
}
}
答案 1 :(得分:0)
我找到了另一种使用HashSet的方式(感谢@Eric J.)。 使用系统; 使用System.Collections.Generic; 使用System.Linq;
class Program
{
static List<int> currentMatchList = new List<int>();
static void Main()
{
int matchSum = int.Parse(Console.ReadLine());
int[] numbers = Console.ReadLine().Split().Select(int.Parse).ToArray();
int combinations = (int)Math.Pow(2, numbers.Length);
List<int> currentSequence = new List<int>();
HashSet<string> allResults = new HashSet<string>();
bool foundMatch = false;
for (int i = 1; i < combinations; i++)
{
for (int bit = 0; bit < Convert.ToString(i, 2).Length; bit++)
{
int mask = (i >> bit) & 1;
if (mask == 1)
{
currentSequence.Add(numbers[numbers.Length - bit - 1]);
}
}
if (currentSequence.Sum() == matchSum)
{
string temp = "";
currentSequence.OrderBy(a => a).ToList().ForEach(a => temp += a + " ");
if (!allResults.Contains(temp))
{
allResults.Add(temp);
Console.WriteLine("{0} = {1}", string.Join(" + ", currentSequence), matchSum);
}
foundMatch = true;
}
currentSequence.Clear();
}
if (!foundMatch)
{
Console.WriteLine("No matching subsets.");
}
}
}