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;
        }
    }
}