给定多个区间,选择数字组合以达到给定的总和。

huangapple go评论64阅读模式
英文:

given multiple ranges select combination of numbers to reach the given sum

问题

public static void main(String[] args) {
    int rangeStart1 = 1;
    int rangeEnd1 = 6;

    int rangeStart2 = 3;
    int rangeEnd2 = 6;

    int rangeStart3 = 2;
    int rangeEnd3 = 5;

    int sum = 13;
    int obtainedSum = 0;
    int randomNum1 = 0;
    int randomNum2 = 0;
    int randomNum3 = 0;
    while (obtainedSum != sum) {
        randomNum1 = (int)((Math.random() * (rangeEnd1 - rangeStart1)) + rangeStart1);
        randomNum2 = (int)((Math.random() * (rangeEnd2 - rangeStart2)) + rangeStart2);
        randomNum3 = (int)((Math.random() * (rangeEnd3 - rangeStart3)) + rangeStart3);
        obtainedSum = obtainedSum + randomNum1 + randomNum2 + randomNum3;
    }

    System.out.println(obtainedSum);
    System.out.println(randomNum1);
    System.out.println(randomNum2);
    System.out.println(randomNum3);
}
英文:

Given the ranges i.e (1-6), (3-6), (2-5) and sum to be reached is 13. I should be able to pick numbers from each range so that their sum is 13.

Example Output : (3,5,5) , (4,4,5) etc

I am trying this out with java code and not able to figure out the exact implementation. I need to generate random number within this range and check for the sum of those numbers. Here there is danger of infinite loop. Could you please help me with this.

public static void main(String[] args) {
    int rangeStart1 = 1;
    int rangeEnd1 = 6;

    int rangeStart2 = 3;
    int rangeEnd2 = 6;

    int rangeStart3 = 2;
    int rangeEnd3 = 5;

    int sum = 13;
    int obtainedSum = 0;
    int randomNum1 = 0;
    int randomNum2 = 0;
    int randomNum3 = 0;
    while (obtainedSum != sum) {
        randomNum1 = (int)((Math.random() * (rangeEnd1 - rangeStart1)) + rangeStart1);
        randomNum2 = (int)((Math.random() * (rangeEnd2 - rangeStart2)) + rangeStart2);
        randomNum3 = (int)((Math.random() * (rangeEnd3 - rangeStart3)) + rangeStart3);
        obtainedSum = obtainedSum + randomNum1 + randomNum2 + randomNum3;
    }

    System.out.println(obtainedSum);
    System.out.println(randomNum1);
    System.out.println(randomNum2);
    System.out.println(randomNum3);
}

答案1

得分: 0

以下为你提供的代码的翻译部分:

为了找到数值数组中给定排列的数字,使其和等于给定的总和,你可以使用暴力算法找到可能的组合。为了实现这一点,你可以使用深度优先搜索(DFS)算法,每次从每个数组中选择一个数字来构建路径。

对于你的示例输入 { [1-6], [3-6], [2-5] }(包括端点),一个有效的路径可以是 1 > 3 > 2(分别从每个数组中选择一个数字)。通过递归,你可以评估所有可能的路径,并找到与给定总和相匹配的路径。

首先,使用 Java 记录(record)语法来定义一些必要的内容,以避免不必要的样板代码。如果需要,你可以将这些类退回到较低的 Java 版本中。

// 选择数字的输入范围
public record Range(int startInclusive, int endInclusive) {

    @Override
    public String toString() {
        return "[" + startInclusive + "," + endInclusive + "]";
    }
}

// 图中的一个节点包含选择的数字和范围
public record Node(Range range, int number) {
    
    @Override
    public String toString() {
        return number + " from " + range.toString();
    }
}

// 图中多个节点的连接
public record Path(Collection<Node> nodes) {

    public static Path EMPTY = new Path(Collections.emptyList());

    // 所有当前节点的和
    public int sum() {
        int sum = 0;
        for (Node s : nodes()) {
            sum += s.number;
        }
        return sum;
    }

    // 将节点添加到此路径的副本
    public Path with(Node node) {
        List<Node> nodes = new ArrayList<>(nodes());
        nodes.add(node);
        return new Path(nodes);
    }
}

现在,创建一个 PathContext 类,用于在递归过程中存储必要的信息。

public class PathContext {

    private final Range[] ranges;
    private final int sum;

    // 与总和匹配的结果路径
    private final Collection<Path> paths = new ArrayList<>();
    // 查找所有匹配还是仅一个(后者更快)
    private final boolean skipAfterMatch = false;

    public PathContext(Collection<Range> ranges, int sum) {
        this.ranges = ranges.toArray(new Range[0]);
        this.sum = sum;
    }

    // 如果路径是有效的解,将其添加到结果中
    public void validatePath(Path path) {
        if (path.sum() == sum) {
            paths.add(path);
        }
    }

    public Range[] getRanges() {
        return ranges;
    }

    public Collection<Path> getPaths() {
        return Collections.unmodifiableCollection(paths);
    }

    public int getSum() {
        return sum;
    }
    
    public boolean abortSearch() {
        return skipAfterMatch && !paths.isEmpty();
    }
}

最后,是深度优先搜索(DFS)的实现:

public static void dfs(PathContext ctx, int rangeIdx, Path path) {
    // 如果没有更多的范围可供选择,则验证是否总和匹配
    if (rangeIdx >= ctx.getRanges().length) {
        ctx.validatePath(path);
    } else {
        // 获取下一个范围
        Range next = ctx.getRanges()[rangeIdx];

        // 遍历范围内的所有数字,包括端点
        for (int i = next.startInclusive; i <= next.endInclusive; i++) {
            // 生成新的节点和路径
            Node node = new Node(next, i);
            Path newPath = path.with(node);

            // 递归处理下一个范围
            dfs(ctx, rangeIdx + 1, newPath);

            // 检查是否可以终止搜索(如果仅需要一个匹配)
            if (ctx.abortSearch()) {
                break;
            }
        }
    }
}

然后,你可以使用你的示例数据调用 dfs 函数:

public static void main(String[] args) {
    Range range1 = new Range(1, 6);
    Range range2 = new Range(3, 6);
    Range range3 = new Range(2, 5);
    List<Range> ranges = List.of(range1, range2, range3);

    PathContext ctx = new PathContext(ranges, 13);
    // 从索引 0 开始(第一个范围)
    dfs(ctx, 0, Path.EMPTY);

    // 输出日志
    System.out.println("总和:" + ctx.getSum());
    for (Path path : ctx.getPaths()) {

        for (Node node : path.nodes()) {
            System.out.println(node);
        }
        System.out.println();
    }
}

最终的输出结果为:

总和:13
2 from [1,6]
6 from [3,6]
5 from [2,5]

3 from [1,6]
5 from [3,6]
5 from [2,5]

3 from [1,6]
6 from [3,6]
4 from [2,5]

4 from [1,6]
4 from [3,6]
5 from [2,5]

...
英文:

To find given permutations of numbers from numeric arrays that match a given sum, you can use a brute-force algorithm to find possible combinations. To achieve that, you can use a depth-first-search in a build by picking one number from each array at a time to construct a path.

For your example input { [1-6], [3-6], [2-5] } (end inclusive), a valid path could be 1 &gt; 3 &gt; 2 (first number from each array). With recursion, you can evaluate all possible paths and find the ones that match the given sum.

First, some definitions using Java record syntax to avoid unneccessary boilerplate code. You can backport the classes to lower Java versions if needed.

// input range to pick numbers from
public record Range(int startInclusive, int endInclusive) {

    @Override
    public String toString() {
        return &quot;[&quot; + startInclusive + &quot;,&quot; + endInclusive + &quot;]&quot;;
    }
}

// a node in the graph contains the picked number and the range
// that this number has been picked from
public record Node(Range range, int number) {
    
    @Override
    public String toString() {
        return number + &quot; from &quot; + range.toString();
    }
}

// connection of multiple nodes in a graph
public record Path(Collection&lt;Node&gt; nodes) {

    public static Path EMPTY = new Path(Collections.emptyList());

    // sum of all current nodes
    public int sum() {
        int sum = 0;
        for (Node s : nodes()) {
            sum += s.number;
        }
        return sum;
    }

    // copy of this path with the node added
    public Path with(Node node) {
        List&lt;Node&gt; nodes = new ArrayList&lt;&gt;(nodes());
        nodes.add(node);
        return new Path(nodes);
    }
}

Now, a PathContext that stores neccessary information used during recursion.

public class PathContext {

    private final Range[] ranges;
    private final int sum;

    // resulting paths that match the sum
    private final Collection&lt;Path&gt; paths = new ArrayList&lt;&gt;();
    // find all matches or just one (latter is faster)
    private final boolean skipAfterMatch = false;

    public PathContext(Collection&lt;Range&gt; ranges, int sum) {
        this.ranges = ranges.toArray(new Range[0]);
        this.sum = sum;
    }

    // if the path a valid solution, add it the the results
    public void validatePath(Path path) {
        if (path.sum() == sum) {
            paths.add(path);
        }
    }

    public Range[] getRanges() {
        return ranges;
    }

    public Collection&lt;Path&gt; getPaths() {
        return Collections.unmodifiableCollection(paths);
    }

    public int getSum() {
        return sum;
    }
    
    public boolean abortSearch() {
        return skipAfterMatch &amp;&amp; !paths.isEmpty();
    }
}

Now finally, the dfs (depth-first-search):

public static void dfs(PathContext ctx, int rangeIdx, Path path) {
    // if we have no more ranges to pick from, validate if the sum matches
    if (rangeIdx &gt;= ctx.getRanges().length) {
        ctx.validatePath(path);
    } else {
        // get the next range
        Range next = ctx.getRanges()[rangeIdx];

        // traverse trough all numbers in the range, end inclusive
        for (int i = next.startInclusive; i &lt;= next.endInclusive; i++) {
            // generate a new node and path
            Node node = new Node(next, i);
            Path newPath = path.with(node);

            // recurse with the next range
            dfs(ctx, rangeIdx + 1, newPath);

            // check if the search can be aborted (if only one match is needed)
            if (ctx.abortSearch()) {
                break;
            }
        }
    }
}

You can then call dfs using your example data:

public static void main(String[] args) {
    Range range1 = new Range(1, 6);
    Range range2 = new Range(3, 6);
    Range range3 = new Range(2, 5);
    List&lt;Range&gt; ranges = List.of(range1, range2, range3);

    PathContext ctx = new PathContext(ranges, 13);
    // start from index 0 (the first range)
    dfs(ctx, 0, Path.EMPTY);

    // output logging
    System.out.println(&quot;total sum: &quot; + ctx.getSum());
    for (Path path : ctx.getPaths()) {

        for (Node node : path.nodes()) {
            System.out.println(node);
        }
        System.out.println();
    }
}

Resulting output is:

total sum: 13
2 from [1,6]
6 from [3,6]
5 from [2,5]

3 from [1,6]
5 from [3,6]
5 from [2,5]

3 from [1,6]
6 from [3,6]
4 from [2,5]

4 from [1,6]
4 from [3,6]
5 from [2,5]

4 from [1,6]
5 from [3,6]
4 from [2,5]

4 from [1,6]
6 from [3,6]
3 from [2,5]

5 from [1,6]
3 from [3,6]
5 from [2,5]

5 from [1,6]
4 from [3,6]
4 from [2,5]

5 from [1,6]
5 from [3,6]
3 from [2,5]

5 from [1,6]
6 from [3,6]
2 from [2,5]

6 from [1,6]
3 from [3,6]
4 from [2,5]

6 from [1,6]
4 from [3,6]
3 from [2,5]

6 from [1,6]
5 from [3,6]
2 from [2,5]

huangapple
  • 本文由 发表于 2020年9月23日 01:19:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/64014706.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定