Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 确定可能项目组的算法_Java_Algorithm - Fatal编程技术网

Java 确定可能项目组的算法

Java 确定可能项目组的算法,java,algorithm,Java,Algorithm,我抓挠我的头试图这样做,它吃了我。我知道没有那么复杂。我有一些项目,这个数字可以等于或大于三。然后我需要确定一组项目的可能组合,以完成总数。唯一的限制是小组应该有三个或更多的项目,不超过(但包括)七个项目 例如: 如果我有7个项目,那么我可以有以下可能的组: 1组7项 1组4项和1组3项 如果我有12个项目,我可以有以下可能的组: 4组3项 3组4项 2组6项 1组7项+1组5项 2组3项,1组6项 1组3项、1组4项和1组5项 我考虑了递归并开始实现算法。这显然不起作用。我不擅长递归

我抓挠我的头试图这样做,它吃了我。我知道没有那么复杂。我有一些项目,这个数字可以等于或大于三。然后我需要确定一组项目的可能组合,以完成总数。唯一的限制是小组应该有三个或更多的项目,不超过(但包括)七个项目

例如:

如果我有7个项目,那么我可以有以下可能的组:

  • 1组7项
  • 1组4项和1组3项
如果我有12个项目,我可以有以下可能的组:

  • 4组3项
  • 3组4项
  • 2组6项
  • 1组7项+1组5项
  • 2组3项,1组6项
  • 1组3项、1组4项和1组5项
我考虑了递归并开始实现算法。这显然不起作用。我不擅长递归。很多

//Instance Fields
public List<ArrayList<String>> options;

//Method that will generate the options. The different options are 
//stored in a list of "option". An individual option will store a list of
//strings with the individual groups.
public void generateOptions(int items, ArrayList<String> currentOption){

    //If the current option is null, then create a new option.
    if(currentOption == null){
        currentOption = new ArrayList<String>();
    }
    if(items < 3){
        //If the number of items is less than three then it doesn't comply with the 
        //requirements (teams should be more or equal than three. 
        currentOption.add("1 group of "+items+" items");
        options.add(currentOption);
    }
    else{
        //I can make groups of 3,4,5,6 and 7 items.
        for(int i = 3;i<=7;i++){
            if(items%i == 0){ 
                // If the number of items is divisible per the current number, 
                // then a possible option could be items/i groups of i items. 
                // Example: Items = 9. A possible option is 3 groups of 3 items.
                currentOption.add(items/i +" groups of "+ i+" items");
                options.add(currentOption);
            }
            else{
                // If the number of items - the current number is equal or greater than
                // three, then a possible option could be a group of i items
                // and then I'll have items-i items to separate in other groups.
                if(items - i >=3){
                    currentOption.add("1 group of "+i+" items");
                    generateOptions(items-i,currentOption);
                }
            }
        }
    }
}
//实例字段
公开列表选项;
//方法,该方法将生成选项。不同的选择是
//存储在“选项”列表中。单个选项将存储
//使用单个组的字符串。
公共void生成选项(int项,ArrayList currentOption){
//如果当前选项为空,则创建一个新选项。
如果(currentOption==null){
currentOption=新的ArrayList();
}
如果(项目<3){
//如果项目数量少于三个,则不符合
//要求(团队人数应大于或等于三人。
currentOption.add(“1组“+项目+”项目”);
选项。添加(当前选项);
}
否则{
//我可以将3、4、5、6和7个项目分组。

对于(int i=3;i这将是只包含集合[3,7]中整数的n的数量

与常规分区问题类似(元素可以是任何正整数):

我看不到与此约束完全匹配的现有数字序列,但您可以像这样(在python中)对组进行计数。这可以取任意范围(在本例中为[3,7]),并对所有a、b、c、d、e(3*a+4*b+5*c+6*d+7*e)和n的序列进行计数

import sys

# All partitions for a particular n:

def groups(n, base, minBase, sum, sets, group = []):
  c = 0; i = (n - sum) / base
  while i >= 0:
    s = sum + base * i
    if s == n:
      sets.append(group + [i]);
      c = c + 1
    elif s < n and base > minBase:
      c = c + groups(n, base - 1, minBase, s, sets, (group + [i]))
    i = i - 1
  return c

# Partitions for each n in [1,maxNum]

def run(maxNum):
  for i in xrange(1, maxNum + 1):
    sets = []; maxBase = 7; minBase = 3
    n = groups(i, maxBase, minBase, 0, sets)
    print '    %d has %d groups:\n' % (i, n)
    for g in sets:
      x = len(g) - 1
      sys.stdout.write('      ')
      while x >= 0:
        if g[x] > 0:
          if x < len(g) - 1: sys.stdout.write(' + ')
          sys.stdout.write('(%d * %d)' % (maxBase - x, g[x]))
        x = x - 1
      print ''
    if len(sets): print ''

run(40)

或者@Cletus的优秀解决方案,它可以通过递归来实现。你不能说你只是想知道可能性的数量还是实际的可能性

你要做的一件事是避免重复,这意味着不要把4和3也算作3和4。一种方法是创建非递减组大小的序列

最好的数据结构可能是树:

root
+- 12
+- 9
|  +- 3
+- 8
|  +- 4
+- 7
|  +- 5
+- 6
|  +- 6
|  +- 3
|     +- 3
+- 5
|  +- 4
|     +- 3
+- 4
|  +- 4
|     +- 4
+- 3
   +- 3
      +- 3
         +- 3
然后,要找到组合的数量,只需计算叶节点的数量。要找到实际的组合,只需遍历树即可

构建此类树的算法如下所示:

  • 函数构建树(int size、int minSize、树根)
  • 计数
    i
    size
    minSize
  • 使用值
    i
    创建当前节点的子节点
  • 对于从
    minSize
    i
    j
    中小于或等于
    i
    • 创建有价值的新子项
      j
    • 调用'buildTree(j,minSize,新节点)

或者与之非常接近的东西。

我认为树是思考它的最佳方式,但是你可以使用递归来构建一个树,而不必显式地构建树。你可以将根视为你的总数。使用大小为3-7的组,你需要找到一些组的组合,这些组的总和就是你的总数

您可以使用0组7、1组7、2组7等。对于每个值,您可以使用0组6、1组6等。树的第一级将表示使用了多少个7。第二级是使用了多少个6,等等。当您使用x 7时,您需要计算出有多少个6、5、4和3的组合对于每个较低级别(递归调用),您可以使用将总和加至(sum-x*7),依此类推

您的树将始终具有5个级别

使用递归来构建树,这里是一个小的Python代码示例(不尝试修剪树,它将探索整个过程)

这将产生:

0 7's, 0 6's, 0 5's, 0 4's, 4 3's
0 7's, 0 6's, 0 5's, 3 4's, 0 3's
0 7's, 0 6's, 1 5's, 1 4's, 1 3's
0 7's, 1 6's, 0 5's, 0 4's, 2 3's
0 7's, 2 6's, 0 5's, 0 4's, 0 3's
1 7's, 0 6's, 1 5's, 0 4's, 0 3's
这里有一个算法(用C++表示)来解决更一般的问题, 每个分区中可能出现的加数的任意上下界:

#include <iostream>
#include <vector>

using namespace std;

typedef vector<int> Partition;
typedef vector<Partition> Partition_list;

// Count and return all partitions of an integer N using only 
// addends between min and max inclusive.

int p(int min, int max, int n, Partition_list &v)
{
   if (min > max) return 0;
   if (min > n) return 0;     
   if (min == n) {
      Partition vtemp(1,min);
      v.push_back(vtemp);
      return 1;
   }
   else {
     Partition_list part1,part2;
     int p1 = p(min+1,max,n,part1);
     int p2 = p(min,max,n-min,part2);
     v.insert(v.end(),part1.begin(),part1.end());
     for(int i=0; i < p2; i++)
     {
        part2[i].push_back(min);
     }
     v.insert(v.end(),part2.begin(),part2.end());
     return p1+p2;
   }
}

void print_partition(Partition &p)
{
   for(int i=0; i < p.size(); i++) {
      cout << p[i] << ' ';
   }
   cout << "\n";
}

void print_partition_list(Partition_list &pl)
{
   for(int i = 0; i < pl.size(); i++) {
      print_partition(pl[i]);
   }
}

int main(int argc, char **argv)
{
   Partition_list v_master;

   int n = atoi(argv[1]);
   int min = atoi(argv[2]);
   int max = atoi(argv[3]);
   int count = p(min,max,n,v_master);
   cout << count << " partitions of " << n << " with min " << min  ;
   cout << " and max " << max << ":\n" ;
   print_partition_list(v_master);
}
在伪代码中:

List<String> results;

void YourAnswer(int n) {
    GeneratePossiblities("", [3, 4, 5, 6, 7], n);
}

void GeneratePossibilities(String partialResult, List<int> buildingBlocks, int n) {
    if (n == 0) {
        // We have a solution
        results.Add(partialResult);
    } else if (buildingBlocks.IsEmpty()) {
        // Dead-end: there is no solution that starts with the partial result we have and contains only the remaining building blocks
        return;
    } else {
        int first = buildingBlocks.First();
        buildingBlocks.PopFirst();
        for (int i = 0, i < n/first; i++) {
          GeneratePossibilities(partialResult + " " + i + "groups of " + first,
                                buildingBlocks, 
                                n - i * first);
        }
    }
}
列出结果;
无效答案(int n){
生成可能性(“,[3,4,5,6,7],n);
}
无效生成可能性(字符串partialResult、列表构建块、int n){
如果(n==0){
//我们有一个解决办法
结果。添加(部分结果);
}else if(buildingBlocks.IsEmpty()){
//死胡同:没有一个解决方案是从我们已有的部分结果开始的,并且只包含剩余的构建块
返回;
}否则{
int first=buildingBlocks.first();
buildingBlocks.PopFirst();
对于(int i=0,i

前两种情况非常简单。第三种情况,您计算(例如)大小为3的组有多少组-可以是0到n/3之间的任意数字,然后递归使用[4,5,6,7]等函数。

您描述的是不太一般的版本

已经给出的算法非常复杂,这里有一个更简单的算法(在伪代码中,我将把它留给您来翻译成Java
:)


JUNG[有一个树实现可能会有所帮助。我想我理解这一点,但是在这个数据结构中,6和6的两组在哪里表示?6应该分支吗
#include <iostream>
#include <vector>

using namespace std;

typedef vector<int> Partition;
typedef vector<Partition> Partition_list;

// Count and return all partitions of an integer N using only 
// addends between min and max inclusive.

int p(int min, int max, int n, Partition_list &v)
{
   if (min > max) return 0;
   if (min > n) return 0;     
   if (min == n) {
      Partition vtemp(1,min);
      v.push_back(vtemp);
      return 1;
   }
   else {
     Partition_list part1,part2;
     int p1 = p(min+1,max,n,part1);
     int p2 = p(min,max,n-min,part2);
     v.insert(v.end(),part1.begin(),part1.end());
     for(int i=0; i < p2; i++)
     {
        part2[i].push_back(min);
     }
     v.insert(v.end(),part2.begin(),part2.end());
     return p1+p2;
   }
}

void print_partition(Partition &p)
{
   for(int i=0; i < p.size(); i++) {
      cout << p[i] << ' ';
   }
   cout << "\n";
}

void print_partition_list(Partition_list &pl)
{
   for(int i = 0; i < pl.size(); i++) {
      print_partition(pl[i]);
   }
}

int main(int argc, char **argv)
{
   Partition_list v_master;

   int n = atoi(argv[1]);
   int min = atoi(argv[2]);
   int max = atoi(argv[3]);
   int count = p(min,max,n,v_master);
   cout << count << " partitions of " << n << " with min " << min  ;
   cout << " and max " << max << ":\n" ;
   print_partition_list(v_master);
}
$ ./partitions 12 3 7              
6 partitions of 12 with min 3 and max 7:
6 6 
7 5 
4 4 4 
5 4 3 
6 3 3 
3 3 3 3 
$ ./partitions 50 10 20            
38 partitions of 50 with min 10 and max 20:
17 17 16 
18 16 16 
18 17 15 
19 16 15 
20 15 15 
18 18 14 
19 17 14 
20 16 14 
19 18 13 
20 17 13 
19 19 12 
20 18 12 
13 13 12 12 
14 12 12 12 
20 19 11 
13 13 13 11 
14 13 12 11 
15 12 12 11 
14 14 11 11 
15 13 11 11 
16 12 11 11 
17 11 11 11 
20 20 10 
14 13 13 10 
14 14 12 10 
15 13 12 10 
16 12 12 10 
15 14 11 10 
16 13 11 10 
17 12 11 10 
18 11 11 10 
15 15 10 10 
16 14 10 10 
17 13 10 10 
18 12 10 10 
19 11 10 10 
20 10 10 10 
10 10 10 10 10 
List<String> results;

void YourAnswer(int n) {
    GeneratePossiblities("", [3, 4, 5, 6, 7], n);
}

void GeneratePossibilities(String partialResult, List<int> buildingBlocks, int n) {
    if (n == 0) {
        // We have a solution
        results.Add(partialResult);
    } else if (buildingBlocks.IsEmpty()) {
        // Dead-end: there is no solution that starts with the partial result we have and contains only the remaining building blocks
        return;
    } else {
        int first = buildingBlocks.First();
        buildingBlocks.PopFirst();
        for (int i = 0, i < n/first; i++) {
          GeneratePossibilities(partialResult + " " + i + "groups of " + first,
                                buildingBlocks, 
                                n - i * first);
        }
    }
}
p(min, n):
    if min > n: return 0
    if min = n: return 1
    return p(min+1, n) + p(min, n-min)