【问题标题】:How to solve this weird multiple loops scenario (Java or C#)?如何解决这种奇怪的多循环场景(Java 或 C#)?
【发布时间】:2012-02-19 09:42:14
【问题描述】:

我遇到了这个 - 可能是微不足道的 - 循环/组合问题,类似于二进制组合。我不知道如何有效地处理它。考虑这种情况,我需要一个独特的循环来依次遍历所有这些组合:

Round  ABC

01.    000 <- values of A=0, B=0, C=0
02.    001
03.    010
04.    011
05.    100
06.    101
07.    110
08.    111

09.    002
10.    012
11.    102
12.    112
13.    020
14.    021
15.    120
16.    121 <- values of A=1, B=2, C=1
17.    022
18.    122
19.    220
20.    221
21.    222

除了有 12 个字母 (A-L),而且“位”大小不仅仅是 0,1 或 2,而是任何整数(从 0 可能到 1000 或 1024,不要让它变得疯狂)。我知道这是一个巨大的组合负载,但我只会废弃前几个也满足我其他条件的组合。所以不必担心计算的疯狂。

免责声明:订单必须完全如上所示。不是多个 FOR 循环,首先是 C 的 0-1024,然后是 B。

提前谢谢,我似乎找不到“算法”的方法。

更新:添加了 ABC/012 组合的完整序列

问候, 凯特

解释:

我在尝试解决分析硬币/纸币组合的金额问题时遇到了这个问题:

例如 $5001 来找出 x 个最佳组合。

10x $500 + 1x $1
50x $100 + 1x $1
..

现在字母 (A,B,C..) 对应于纸币或硬币的许多可能价值 ($1, $5,.. $100)。而基数对应于该纸币/硬币的数量(例如 $5001/$5000 = 1piece max.)

【问题讨论】:

  • 有趣的序列 - 为什么第二组(值 9 到 16)的第一个位置从来没有“2”?
  • 它确实,它继续:022, 122, 220, 221, 222,..
  • 您可能想解释一下顺序,我发现任何人都不太可能根据您目前给出的内容确定确切的顺序。
  • 我想只要你能用简单的英语表达你需要什么样的序列,你也会有你要找的算法。+
  • 理解序列进展的确切规则本身就是一个挑战。几乎就像智商测试。

标签: c# java algorithm for-loop binary


【解决方案1】:

如果我猜对了你的序列,你会更容易递归地生成它

这里是 Java 中的一种方法,它应该生成一个与您的场景相匹配的序列。 希望对您有所帮助(也许我稍后会添加更多解释):

public static void init() {
    // define constants
    final int length = 3;
    final char maxValue = '3';

    // define buffer
    final char[] array = new char[length]; java.util.Arrays.fill(array, '0');
    final boolean[] alreadySet = new boolean[length]; java.util.Arrays.fill(alreadySet, false);

    // fill first digit, then let the recursion take place
    for(char c = '1'; c <= (char)(maxValue); c++) {
        // iterate from lowest to highest digit
        for(int i = array.length-1; i >= 0; i--) {
            // set value
            array[i] = c;
            alreadySet[i] = true;
            // print value
            System.out.println(new String(array));
            // call recursion
            recursive(array, c, i, alreadySet, length);
            // unset value
            alreadySet[i] = false;
            array[i] = '0';
        }
    }
}

public static void recursive(char[] array, char lastValue, int lastIndex, boolean[] alreadySet, int leftToSet) {
    // if we didn't set all digits
    if(leftToSet > 0) {
        // iterate from lowest to highest digit
        for(int i = array.length-1; i >= 0; i--) {
            // missing all digits already set
            if(!alreadySet[i]) {
                // count from 1 to lastValue-1
                for(char c = '1'; c < lastValue; c++) {
                    // set value
                    array[i] = c;
                    alreadySet[i] = true;
                    // print value
                    System.out.println(new String(array));
                    // call recursion
                    recursive(array, c, i, alreadySet, leftToSet-1);
                    // unset value
                    alreadySet[i] = false;
                    array[i] = '0';
                }
            }
        }

        char c = lastValue;
        // iterate from lowest to highest digit
        for(int i = array.length-1; i > lastIndex; i--) {
            // missing all digits already set
            if(!alreadySet[i]) {
                // set value
                array[i] = c;
                alreadySet[i] = true;
                // print value
                System.out.println(new String(array));
                // call recursion
                recursive(array, c, i, alreadySet, leftToSet-1);
                // unset value
                alreadySet[i] = false;
                array[i] = '0';
            }
        }
    }
}

【讨论】:

  • 我正在尝试实现它,但是我遇到了“丢失所有已设置的数字”的问题?究竟是什么意思?
  • 如果你在 0030 中设置了 3,那么你从 003* 迭代到 0*30 到 030 ;那么如果你在 003 并将它设置为 2 => 0032 你从 0*32 迭代到 *032 ;希望这会让它更清楚
  • 坦率地说,我无法掌握它。我读了几千遍。你能试着扩展一下伪代码吗?
  • 哦,我明白了,格式出了点问题;我稍后会为你展开它
  • 确实如此。我运行了 12 个字母和大约 '4' 的值,它似乎是一致的。非常感谢。哇!
【解决方案2】:

伪 C#/Java 的粗略草图:

将 A-L 映射到索引 0-11

const int[] maxvalues = { define max values for each var }
int[] counters = { initialize with 0s }

while (true)
{
  for(i in 11..0)
  {
    counters[i]++;
    if (counters[i] < maxvalues[i])
      break;   // for
    counters[i] = 0;
  }

  if (counters[0] == maxvalues[0])
    break;     // while

  print(counters.ToDisplayString());
}

(刚刚注意到第二个序列与OP中的第一个序列不匹配。如果OP是正确的,我想我没有“得到”这个序列)

【讨论】:

  • if(counters[0] = maxvalues[0]) 应该是 if(counters[0] == maxvalues[0])
  • 您好,谢谢,我无法通过肉眼确定它是否做了它应该做的事情。给我一点时间试试。 :)
  • @SmartK8:无法匹配,因为没有正式的方式来描述该序列。
  • 这给了我相当于每个字母的循环。因此,如果 C 的最大值为 1000,则它首先变为 0-1000,B 增加 1,然后 C 再次变为 0-1000。不好。
【解决方案3】:

您所描述的数字序列可以通过从 0 向上计数来枚举,在数字的基本表示中,比用于创建单个序列的“字母”数量大一。

执行此操作的一种简单方法是使用以 10 为底的 radix converter,它将作用于在单个循环中从 0 递增到您希望实现的最大组合数的变量。

这是一个实现:

void Main()
{
    for(int i=0; i< 50; i++){
     Console.Write(convert(5,i));
     Console.Write("\n");
    }
}

string convert(int N, int M){
    Stack<int> stack = new Stack<int>();

    while (M >= N){
     stack.Push(M %N);
     M = M / N;
    }
    string str = M.ToString();
    while(stack.Count() > 0)
      str = str + stack.Pop().ToString();
    return str;
}

开始输出:

0 1 2 3 4 10 11 12 13 14 20 21 22 23 24 30 31 32 33 34 40 41 42 43 44 100 101 102 103 104

【讨论】:

  • 我怎样才能解码出多少个字母?
  • 这不会产生 OP 的序列。请注意,她的序列在第 12 和第 15 个元素之间改变 方向(如果观察为基数为 n 的数字)。
  • @Groo,OP 的序列(没有完全解释)似乎是我提供的序列的一个微不足道的变化。
  • 我只是不知道如何将例如 13 解码为 A=1(1 件)、B=2(2 件)、C=1(1 件)?你能详细说明一下吗?
  • (A=1, B=2, C=1 是一个例子)
猜你喜欢
  • 2021-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-25
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多