编程竞赛的实践

时间:2011-03-08 21:00:40

标签: java recursion

我将在几周内参加一个编程竞赛,并一直在处理过去的论文。我坚持的一个问题是调用一个递归函数,它计算所有可能的n位数的二进制整数,例如用户输入2,程序打印出00,01,10,11。解决这个问题的最佳方法是什么?怎么做?

此外,这是一场ACM比赛 - 是否有必要为这些比赛学习书籍?我应该读什么?这是一个月之内!我真的很紧张,不想让我的团队失望。

8 个答案:

答案 0 :(得分:6)

Java中的解决方案:

for(int i = 0; i < 1 << n; i++)
  {
  System.out.println(Integer.toBinaryString(i));
  }

答案 1 :(得分:3)

这里有一些没有实际限制的代码(你可以删除递归,但似乎这是答案的要求):

public class Bits {
  public static void f(String prefix, int n) {
    if (n == 0) {
      System.out.println(prefix);
      return;
    }
    f(prefix + "0", n - 1);
    f(prefix + "1", n - 1);
  }
  public static void main(String [] argv) {
    f("", 5);
  }
}

答案 2 :(得分:2)

在C或C ++中可能是类似的东西,在这种情况下递归性并不是真正必要或更简单,但如果被问到......算法正是我要做的手工解决这个问题。从右到左改变1到0并传播进位,直到找到0.这在基数2中计算。作为一个练习你可以尝试在3或4基数,它没有太大的不同。

#include <stdio.h>
#include <malloc.h>

void f(char *buffer, int max){
    int i;
    printf("%s, ", buffer);
    for (i = max-1 ; buffer[i] == '1' ; i--){
        buffer[i] = '0';
    }
    if (i < 0) return;
    buffer[i] = '1';
    f(buffer, max);
}

int main(int argc, char ** argv){
    int max = atoi(argv[1]);
    char buffer[32];
    int i;
    for (i = 0; i < max ; i++){
        buffer[i] = '0';
    }
    buffer[max] = 0;
    f(buffer, max);
}

为了准备比赛,回顾过去的论文是一个好主意。但基本上你应该尽可能多地编写代码。您还应该训练以实现经典算法(树,排序,图形实现以及搜索最佳路径,列表,8个皇后等),同时您可以寻求帮助。一个月的时间并不是很长,所以你应该专注于理解一些经典问题。

我还建议习惯于单元测试,这样可以避免提出错误的答案,在这种竞争和单元测试中会受到惩罚,TDD无论如何都有助于关注问题,避免浪费你的时间。

答案 3 :(得分:1)

这不是java,但它是递归的。

function getBinaryDigitForPosition(currentLevel, currentNumberAsString) {

  // if this were anything but binary I'd put these into an array and iterate thru
  firstNumber = currentNumberAsString + "0";
  secondNumber = currentNumberAsString + "1";

  if (currentLevel == 1) {
    print firstNumber + ", " + secondNumber;
  } else {
    // same iteration here as I mentioned above
    getBinaryDigitForPosition(currentLevel - 1, firstNumber);
    getBinaryDigitForPosition(currentLevel - 1, secondNumber);
  }

}

// calling the function initially:
// make sure that userInputNumberOfDigits is >= 1

getBinaryDigitForPosition(userInputNumberOfDigits, "");

答案 4 :(得分:0)

编辑我写错了这个问题 - 这是用k位打印出长度为N的所有字符串。留下这个作为竞赛的建议。

有一个比O(2^n)更好的解决方案,这里有一个提示 - 考虑长度为N的位串数与k个位的递归关系。设S是一个计算这些项数的函数

S(N,k) = S(N-1,k-1) + S(N-1,k)

用语言来说,重复归结为此 - 你可以添加一点或不添加一点。您可以使用memoization使此计算快速运行。你需要自己重现弦乐,但我把它留作练习。

通过阅读书籍可以学到很多东西(算法和算法设计手册介绍很好),以获得“全局”算法。剩下的就是有经验来找到那些算法何时适合这些问题,何时不适合以及如何在这种情况下编写特殊解决方案。我已经完成了其中的一些,但不能说我擅长他们,玩得开心,祝你好运:)

答案 5 :(得分:0)

这是一个java递归解决方案:)

 public class BinaryIntegers {

    public static void main(String[] args) {
        int numberOfBits = 10; // For instance.
        printBinaryNumbers(numberOfBits);
    }

    private static void printBinaryNumbers(int numberOfBits) {
        recursivePrint("", numberOfBits);
    }

    private static void recursivePrint(String current, int numberOfBitsLeft){
        if(numberOfBitsLeft==0)
            System.out.println(current);
        else{
            recursivePrint(current + "0", numberOfBitsLeft-1);
            recursivePrint(current + "1", numberOfBitsLeft-1);
        }
    }
}

答案 6 :(得分:0)

这是一个更通用的解决方案,它不仅可以创建二进制数字列表,还可以创建任何数字列表: - )

package de.fencing_game.paul.examples;

import java.util.Arrays;


public class AllNaryNumbers {


    private static void printAll(String prefix, Iterable<String> digits,
                                int length)
    {
        if(length == 0) {
            System.out.println(prefix);
            return;
        }
        for(String digit : digits) {
            printAll(prefix + digit, digits, length-1);
        }
    }

    private static void printNumbers(int length, Iterable<String> digits) {
        printAll("", digits, length);
    }

    private static void printBinary(int length) {
        printNumbers(length, Arrays.asList("0", "1"));
    }

    public static void main(String[] params) {
        if(params.length == 0) {
            printBinary(5);
            return;
        }
        int len = Integer.parseInt(params[0]);
        if(params.length == 1) {
            printBinary(len);
            return;
        }
        Iterable<String> digits =
            Arrays.asList(params).subList(1, params.length);
        printNumbers(len, digits);
    }

}

编辑:使用我的ProductIterable时,代码会变短:

private static void printNumbers(int length, Iterable<String> digits)
{
    for(List<String> number :
            new ProductIterable<String>
            (Collections.nCopies(length, digits))) {
        for(String digit : number) {
            System.out.print(digit);
        }
        System.out.println();
    }
}

(大部分是将Iterable转换为字符串)。如果我们可以使用以逗号分隔的输出,我们可以使用ProductList并使其更短:

private static void printNumbers(int length, List<String> digits)
{
    System.out.println(new ProductList<String>
                       (Collections.nCopies(length, digits)));
}

输出将是这样的:[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]

它不是递归的,但至少是懒惰的(及时)产生元素。

答案 7 :(得分:0)

有一本书:

http://www.amazon.com/exec/obidos/ISBN=0387001638/theinternationscA/

我的一个朋友收到了这样一本书(作为初级编程竞赛的价格),并且非常热衷于此,但我不确定它是否是这个(虽然它确实在亚马逊上有很好的评价)

准备的最佳方法是解决旧的编程问题。检查过去的问题集,总会出现一些问题:迷宫中的东西,动态编程的东西等。练习这些类型的问题,这样你就可以在真正的竞争中快速解决它们。

另外,不要低估参与编程竞赛的计划/组织的数量。团队成员之间的良好互动(例如,挑选哪些练习要解决)非常重要。也是如何修复错误程序的好方法。

另一件事,你说你真的很紧张,害怕让你的团队失望。但请记住,你是一个团队。一起练习!! 如果你要三个人去那里,你肯定会失去......(最好的方法就是失败:让一个团队成员声称某个问题,他不会解决,但是其中他确信自己“几乎就在那里”;从而占用了大量的计算机时间,并且没有任何解决方案......)

另外,想想你将如何工作。我个人最喜欢的是两个编码器和一个非编码器。这样,总有一个人使用计算机,而另一个编码器可以讨论非编码器的问题。 (通过编码器,我的意思是实际键入代码的人,而不仅仅是在纸上编写算法)

祝你好运!更重要的是:玩得开心!