Arrays 使用给定集合中的值计算得到N的所有可能性
问题是: 给定Arrays 使用给定集合中的值计算得到N的所有可能性,arrays,algorithm,Arrays,Algorithm,问题是: 给定输入=[100 80 66 25 4 2 1],我需要找到最佳组合,以获得50 看这个,最好是25+25=50,所以我需要数组中的2个元素 其他组合包括25+4+4+4+4+4+4+1和25+4+4+4+4+4+2+1。。等等 我需要找到所有的可能性,这些可能性给了我一个我想要的值的总和 编辑:以及最佳可能性(条款数量最少的条款) 以下是我迄今为止所做的工作: 首先构建一个新数组(simple for loop循环遍历所有元素并存储在一个新的临时数组中),检查所有高于我的数组的元素
输入=[100 80 66 25 4 2 1]
,我需要找到最佳组合,以获得50
看这个,最好是25+25=50,所以我需要数组中的2个元素
其他组合包括25+4+4+4+4+4+4+1
和25+4+4+4+4+4+2+1
。。等等
我需要找到所有的可能性,这些可能性给了我一个我想要的值的总和
编辑:以及最佳可能性(条款数量最少的条款)
以下是我迄今为止所做的工作:
首先构建一个新数组(simple for loop循环遍历所有元素并存储在一个新的临时数组中),检查所有高于我的数组的元素(因此对于输入50,元素100,80,66更高,所以丢弃它们,然后我的新数组是[25 4 2 1])。然后,从这里,我需要检查组合
我要做的第一件事是一个简单的if语句,检查是否有任何数组元素与我想要的数字完全匹配。如果我想要50,我检查数组中是否有50,如果没有,我需要找到组合
我的问题是,我不完全确定如何找到每一个组合。一段时间以来,我一直在努力想出一个算法,但最终总是被难倒
如有任何帮助/提示,将不胜感激
PS-我们可以假设数组总是按从最大值到最小值的顺序排序。您需要解决每个子问题并存储解决方案。例如: 1只能是1。2可以是2或1+1。4可以是4或2+2或2+1+1或1+1+1。因此,您获取每个子解并存储它,因此当您看到25=4+4+4+4+4+1时,您已经知道每个4也可以表示为3个组合中的一个 然后您必须对数字进行排序并进行检查以避免重复模式,例如,(2+2)+(2+2)+(2+2)+(1+1+1)+(1+1+1)+(1+1+1)==(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)。两种情况下都有6个2和12个1
这有意义吗?递归应该是解决这个问题的最简单方法(假设您真的想找到问题的所有解决方案)。这种方法的好处是,如果您只想找到最短的解决方案,您可以添加对递归的检查并找到它,从而节省时间和空间:) 假设数组的元素
i
是解决方案的一部分,则可以解决查找与n-i
求和的元素的子问题。如果我们给我们的解决方案添加一个排序,例如,总和中的数字必须从大到小,我们就有办法找到唯一的解决方案
这是一个C#中的递归解决方案,用java翻译应该很容易
public static void RecursiveSum(int n, int index, List<int> lst, List<int> solution)
{
for (int i = index; i < lst.Count; i++)
{
if (n == 0)
{
Console.WriteLine("");
foreach (int j in solution)
{
Console.Write(j + " ");
}
}
if (n - lst[i] >= 0)
{
List<int> tmp = new List<int>(solution);
tmp.Add(lst[i]);
RecursiveSum(n - lst[i], i, lst, tmp);
}
}
}
publicstaticvoidrecursivesum(int n,int index,List lst,List solution)
{
for(int i=索引;i=0)
{
列表tmp=新列表(解决方案);
tmp.Add(lst[i]);
递归和(n-lst[i],i,lst,tmp);
}
}
}
你把它叫做
RecursiveSum(N,0,list,new List<int>());
RecursiveSum(N,0,list,newlist());
其中N是您要查找的总和,0不应更改,list是您允许的数字列表,最后一个参数也不应更改。这就是动态规划要解决的问题
创建一个索引为1到50的数组。将每个条目设置为-1。对于输入数组中的每个元素,将数组中的该元素设置为0。然后,对于每个整数n=2到50,找到所有可能的方法求和到n。所需的和数是两个加数加1的最小值。最后,获取索引50处的元素。编辑:由于对问题的误解,我首先用一种有效的方法来回答问题,即使用给定集合中的值计算得到N的可能性数(而不是可能性本身)。这个解决方案可以在这篇文章的底部找到,作为其他人的参考,但首先我会给你的问题一个正确的答案
生成所有可能性,计算它们并给出最短的可能性 当生成一个解决方案时,从输入数组中考虑每个元素,并问自己:“我应该在解决方案中使用这个元素吗?”因为我们在计算之后才知道答案,所以我们只能尝试使用它和不使用它,正如下面代码中的递归步骤所示 现在,为了避免重复和未命中,我们需要小心处理递归调用的参数。如果我们使用当前元素,我们还应该允许在下一步中使用它,因为该元素可以被尽可能多地使用。因此,此递归调用中的第一个参数是
i
。但是,如果我们决定不使用该元素,我们就不应该在下一步中使用它,因为这将是当前步骤的重复。因此,此递归调用中的第一个参数是i+1
我在算法中添加了一个可选的边界(从“”),如果知道当前部分解永远不会比目前找到的最短解短,则该边界将停止扩展当前部分解
package问题;
导入java.util.Deque;
导入java.util.LinkedList;
公共类生成可能性
{
//输入
私有静态int n=50;
//如果输入数组按升序排序,则最短的解决方案为
//可能在最后的某个地方找到。
//如果输入数组按降序排序,则最短的解决方案为
//可能在一开始的某个地方找到。
私有静态int[]输入={100,80,66,25,4,2,1};
//
array = [70 30 25 4 2 1]
value = 50
sort(array, descending)
solutions = [] // array of arrays
while length of array is non-zero:
tmpValue = value
thisSolution = []
for each i in array:
while tmpValue >= i:
tmpValue -= i
thisSolution.append(i)
solutions.append(thisSolution)
array.pop_first() // remove the largest entry from the array
[[30 4 4 4 4 4]
[30 4 4 4 4 4]
[25 25]
[4 4 4 4 4 4 4 4 4 4 4 4 2]
[2 ... ]
[1 ... ]]
array = [70, 30, 25, 4, 3, 1]
def findSmallest(value, array):
minSolution = []
tmpArray = list(array)
while len(tmpArray):
elem = tmpArray.pop(0)
tmpValue = value
cnt = 0
while tmpValue >= elem:
cnt += 1
tmpValue -= elem
subSolution = findSmallest(tmpValue, tmpArray)
if tmpValue == 0 or subSolution:
if not minSolution or len(subSolution) + cnt < len(minSolution):
minSolution = subSolution + [elem] * cnt
return minSolution
print findSmallest(10, array)
print findSmallest(50, array)
print findSmallest(49, array)
print findSmallest(55, array)
[3, 3, 4]
[25, 25]
[3, 4, 4, 4, 4, 30]
[30, 25]
abstract class Numbers {
abstract int total();
public static Numbers breadthFirst(int[] numbers, int total) {
List<Numbers> stack = new LinkedList<Numbers>();
if (total == 0) { return new Empty(); }
stack.add(new Empty());
while (!stack.isEmpty()) {
Numbers nums = stack.remove(0);
for (int i : numbers) {
if (i > 0 && total - nums.total() >= i) {
Numbers more = new SomeNumbers(i, nums);
if (more.total() == total) { return more; }
stack.add(more);
}
}
}
return null; // No answer.
}
}
class Empty extends Numbers {
int total() { return 0; }
public String toString() { return "empty"; }
}
class SomeNumbers extends Numbers {
final int total;
final Numbers prev;
SomeNumbers(int n, Numbers prev) {
this.total = n + prev.total();
this.prev = prev;
}
int total() { return total; }
public String toString() {
if (prev.getClass() == Empty.class) { return "" + total; }
return prev + "," + (total - prev.total());
}
}
public static class SAR
{
//I'm considering Optimal as the smallest signature (number of members).
// Once set, all future signatures must be same or smaller.
private static Random _seed = new Random();
private static List<int> _domain = new List<int>() { 100, 80, 66, 24, 4, 2, 1 };
public static void SetDomain(string domain)
{
_domain = domain.Split(',').ToList<string>().ConvertAll<int>(a => Convert.ToInt32(a));
_domain.Sort();
}
public static void FindOptimalSAR(int value)
{
// I'll skip some obvious tests. For example:
// If there is no odd number in domain, then
// it's impossible to find a path to an odd
// value.
//Determining a max path run. If the count goes
// over this, it's useless to continue.
int _maxCycle = 10;
//Determining a maximum number of runs.
int _maxRun = 1000000;
int _run = 0;
int _domainCount = _domain.Count;
List<int> _currentOptimalSig = new List<int>();
List<String> _currentOptimalOps = new List<string>();
do
{
List<int> currSig = new List<int>();
List<string> currOps = new List<string>();
int _cycle = 0;
int _cycleTot = 0;
bool _OptimalFound = false;
do
{
int _cursor = _seed.Next(_domainCount);
currSig.Add(_cursor);
if (_cycleTot < value)
{
currOps.Add("+");
_cycleTot += _domain[_cursor];
}
else
{
// Your situation doesn't allow for negative
// numbers. Otherwise, just enable the two following lines.
// currOps.Add("-");
// _cycleTot -= _domain[_cursor];
}
if (_cycleTot == value)
{
_OptimalFound = true;
break;
}
_cycle++;
} while (_cycle < _maxCycle);
if (_OptimalFound)
{
_maxCycle = _cycle;
_currentOptimalOps = currOps;
_currentOptimalSig = currSig;
Console.Write("Optimal found: ");
for (int i = 0; i < currSig.Count; i++)
{
Console.Write(currOps[i]);
Console.Write(_domain[currSig[i]]);
}
Console.WriteLine(".");
}
_run++;
} while (_run < _maxRun);
}
}
String _Domain = "100, 80, 66, 25, 4, 2, 1";
SAR.SetDomain(_Domain);
Console.WriteLine("SAR for Domain {" + _Domain + "}");
do
{
Console.Write("Input target value: ");
int _parm = (Convert.ToInt32(Console.ReadLine()));
SAR.FindOptimalSAR(_parm);
Console.WriteLine("Done.");
} while (true);
SAR for Domain {100, 80, 66, 24, 4, 2, 1}
Input target value: 50
Optimal found: +24+24+2.
Done.
Input target value: 29
Optimal found: +4+1+24.
Done.
Input target value: 75
Optimal found: +2+2+1+66+4.
Optimal found: +4+66+4+1.
Done.
SAR for Domain {100, 80, 66, 25, 4, 2, 1}
Input target value: 50
Optimal found: +25+25.
Done.
Input target value: 75
Optimal found: +25+25+25.
Done.
Input target value: 512
Optimal found: +80+80+66+100+1+80+25+80.
Optimal found: +66+100+80+100+100+66.
Done.
Input target value: 1024
Optimal found: +100+1+80+80+100+2+100+2+2+2+25+2+100+66+25+66+100+80+25+66.
Optimal found: +4+25+100+80+100+1+80+1+100+4+2+1+100+1+100+100+100+25+100.
Optimal found: +80+80+25+1+100+66+80+80+80+100+25+66+66+4+100+4+1+66.
Optimal found: +1+100+100+100+2+66+25+100+66+100+80+4+100+80+100.
Optimal found: +66+100+100+100+100+100+100+100+66+66+25+1+100.
Optimal found: +100+66+80+66+100+66+80+66+100+100+100+100.
Done.
# Start of tsum function
def tsum(currentSum,total,input,record,n):
if total == N :
for i in range(0,n):
if record[i]:
print input[i]
i = i+1
for i in range(i,n):
if record[i]:
print input[i]
print ""
return
i=currentSum
for i in range(i,n):
if total+input[i]>sum :
continue
if i>0 and input[i]==input[i-1] and not record[i-1] :
continue
record[i]=1
tsum(i+1,total+input[i],input,record,l)
record[i]=0
# end of function
# Below portion will be main() in Java
record = []
N = 5
input = [3, 2, 2, 1, 1]
temp = list(set(input))
newlist = input
for i in range(0, len(list(set(input)))):
val = N/temp[i]
for j in range(0, val-input.count(temp[i])):
newlist.append(temp[i])
# above logic was to create a newlist/input i.e [3, 2, 2, 1, 1, 1, 1, 1]
# This new list contains the maximum number of elements <= N
# for e.g appended three 1's as sum of new three 1's + existing two 1's <= N(5) where as
# did not append another 2 as 2+2+2 > N(5) or 3 as 3+3 > N(5)
l = len(input)
for i in range(0,l):
record.append(0)
print "all possibilities to get N using values from a given set:"
tsum(0,0,input,record,l)
import org.apache.commons.lang.ArrayUtils;
import java.util.*;
public class Stuff {
private final int target;
private final int[] steps;
public Stuff(int N, int[] steps) {
this.target = N;
this.steps = Arrays.copyOf(steps, steps.length);
Arrays.sort(this.steps);
ArrayUtils.reverse(this.steps);
this.memoize = new HashMap<Integer, List<Integer>>(N);
}
public List<Integer> solve() {
return solveForN(target);
}
private List<Integer> solveForN(int N) {
if (N == 0) {
return new ArrayList<Integer>();
} else if (N > 0) {
List<Integer> temp, min = null;
for (int i = 0; i < steps.length; i++) {
temp = solveForN(N - steps[i]);
if (temp != null) {
temp.add(steps[i]);
if (min == null || min.size() > temp.size()) {
min = temp;
}
}
}
return min;
} else {
return null;
}
}
}