由于具有非常基本的动态编程经验,我只能在遇到此问题时使用Web。做我的研究,似乎this和this似乎在我所寻找的球场中,但是,我仍然无法绕过什么考虑到所有子集都有8个整数的要求,代码看起来就好了。
例如:
2678
2258
2146
2067
2026
1986
1967
1928
1844
1809
987
981
928
790
752
739
470
400
393
给定这个集合,我必须找到总和小于10000的八个整数的每个组合。
我在这些论坛上发帖很新,所以如果我超越某些界限,请告诉我。任何信息都有帮助! 非常感谢,非常感谢。
答案 0 :(得分:0)
如果你使用c#,你可以使用LINQ作为一个非常强大的工具。使用LINQ,您实际上可以在单行查询中实现您所需的功能。对于你的例子中的整数,有14441种不同的8个整数组合,其总和小于10.000:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
//Set your input parameters.
int[] input = { 2678, 2258, 2146, 2067, 2026, 1986, 1967, 1928, 1844, 1809, 987, 981, 928, 790, 752, 739, 470, 400, 393 };
int SubsetCount = 8;
int MaxSum = 10000;
//Determine all subsets that are meeting your restrictions.
var subsets = Enumerable.Range(0, 1 << input.Length).Select(a => Enumerable.Range(0, input.Length).Where(i => Program.NumberOfSetBits(a) == SubsetCount && (a & (1 << i)) != 0).Select(i2 => input[i2])).Where(sub => sub.Sum() < MaxSum && sub.Sum() >= 1);
//Print the result to the Console.
foreach (IEnumerable<int> sub in subsets)
{
foreach (int s in sub)
{
Console.Write(s.ToString() + "; ");
}
Console.WriteLine();
}
Console.ReadKey();
}
public static int NumberOfSetBits(int i)
{
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
}
}
使用LINQ的解决方案并不像我想象的那样简单,但事实上并不容易阅读。作为编程的初学者,我建议从评论中建议的更为程序化的方法入手:
此外,我没有使用一整套64个整数测试上面的代码。如果运行时是一个问题,那么如果您自己实现查询而不是使用LINQ,则可以执行一些非常合理的优化。 (按大小排序整数 - 并考虑到下一个最高数字的差异 - 将允许您构建一个算法,该算法完全生成所需的结果集,并在您达到超出10.000的限制的组合时立即停止
修改强>
由于我没有正确格式化LINQ查询以提高可读性,我觉得有必要就它正在做的事情提供一些指示:
Enumerable.Range(0, 1<< input.Length)
是从0
到2^input.length
的整数列表,因此包含input
幂集中每个元素的一个整数。我使用它作为查询的基础,这样我们就不必自己生成幂集(请注意,您可以将这些整数的二进制表示一对一地映射到幂集:input [i]包含在当且仅当设置了相应整数中位置i的位时)。
因此,我们可以找到包含8个整数的所有子集,方法是在我们的Range中找到所有整数,并且设置正好8位(我在这里找到了所使用的包含方法NumberOfSetBits
)。
此外,当位置a & (1 << i)
中的位设置为整数1
时,语句i
返回a
(通过向左移动1步并使用逻辑AND操作)。使用这个,我们获得了几个精确8
索引的列表,这些索引适合我们的输入数组中的某些数字。
然后,我们可以继续检查每个集合的总和,并将其与我们的边界进行比较(并检查总和为>0
以从查询结果中排除空集。)
答案 1 :(得分:0)
你说做了一些研究。由于解决方案非常简单,我将提供方法虽然这似乎是功课。 代码(故意)错过了尝试所有数字的短切。
64! / (64 - 8)! / 8!
的候选解决方案的数量有点大。因此减少是应该的。当您需要所有解决方案时,请对64个整数进行排序。然后开始用&amp;没有候选人从下一个职位上撤下。
int[] numbers = ... 64 numbers
Arrays.sort(numbers);
int[] result = new int[8];
solve(result, 0, 0, 0);
void solve(int[] result, int resultIndex, int total, int numberIndex) {
if (resultIndex >= 8) {
if (total <= sum) {
System.out.println(Arrays.toString(result));
}
return;
}
if (numberIndex >= 64) {
return;
}
// Solve without current number
solve(result, resultIndex, total, numberIndex + 1);
// Solve with current number
int currentNumber = numbers[numberIndex];
result[resultIndex] = currentNumber ;
solve(result, resultIndex + 1, total + currentNumber, numberIndex + 1);
}
采取的方法包括尝试新的候选人 - 或者不是 - 并继续其余的。