USACO 2018年12月青铜倒铸错误

时间:2019-01-19 17:22:42

标签: java algorithm

从2018年12月开始的USACO铜牌问题,BackForth问题:http://usaco.org/index.php?page=viewproblem2&cpid=857

我的代码:

import java.util.*;
import java.io.*;
public class backforth
{
    //  static int[] poss = new int[2000];
    static ArrayList<Integer> poss = new ArrayList<Integer>();
    public static void tuesday(int milk, ArrayList<Integer> one, ArrayList<Integer> two)
    {
        for(int i = 0; i < one.size(); i++)
        {
            int x = one.get(i);
//          ArrayList<Integer> twoNew = two; twoNew.add(x);
//          ArrayList<Integer> oneNew = one; oneNew.remove(i);
            two.add(x);
            one.remove(i);
            wednesday(milk - x, one, two);
        }
    }

    public static void wednesday(int milk, ArrayList<Integer> one, ArrayList<Integer> two)
    {
        for(int i = 0; i < two.size(); i++)
        {
            int x = two.get(i);
//          ArrayList<Integer> oneNew = one; oneNew.add(x);
//          ArrayList<Integer> twoNew = two; twoNew.remove(i);
            one.add(x);
            two.remove(i);
            thursday(milk + x, one, two);
        }
    }

    public static void thursday(int milk, ArrayList<Integer> one, ArrayList<Integer> two)
    {
        for(int i = 0; i < one.size(); i++)
        {
            int x = one.get(i);
//          ArrayList<Integer> twoNew = two; twoNew.add(x);
//          ArrayList<Integer> oneNew = one; oneNew.remove(i);
            two.add(x);
            one.remove(i);
            friday(milk - x, one, two);
        }
    }

    public static void friday(int milk, ArrayList<Integer> one, ArrayList<Integer> two)
    {
        for(int i = 0; i < two.size(); i++)
        {
            int x = two.get(i);
            int add = milk + x;
            if(!poss.contains(add))
                poss.add(add);
        }
    }

    public static void main(String[] hi) throws IOException
    {
        BufferedReader in = new BufferedReader(new FileReader("backforth.in"));
        PrintWriter out = new PrintWriter(new File("backforth.out"));
        StringTokenizer st;

        st = new StringTokenizer(in.readLine());
        ArrayList<Integer> B1 = new ArrayList<Integer>();
        ArrayList<Integer> B2 = new ArrayList<Integer>();

        for(int i = 0; i < 10; i++)
        {
            B1.add(Integer.parseInt(st.nextToken()));
        }

        st = new StringTokenizer(in.readLine());
        for(int i = 0; i < 10; i++)
        {
            B2.add(Integer.parseInt(st.nextToken()));
        }
        tuesday(1000, B1, B2);

        //for(int  i = 0; i < poss.size(); i++)
        //  System.out.println(poss.get(i) + " ");
        System.out.println(poss.size());
        in.close();out.close();
    }
}

输出应该为5,但我得到9。我不知道如何修复代码以获取正确的输出-我尝试了几种不同的方法,但没有获得正确的输出。

我在1号仓库中可能获得的牛奶产量

1008 
1004 
1007 
1003 
1005 
1000 
1001 
996 
997 
9

但是,它应该是1000, 1003, 1004, 1007, 1008

1 个答案:

答案 0 :(得分:0)

在将其表述为graph problem时,您的方法非常正确;在给定的一天,您会在谷仓中的每个存储桶上循环并尝试携带它,并在唯一的时候存储星期五的最终结果。

但是,要使其正常工作,每次您从谷仓中提起一个水桶并递归到子状态时,都需要“撤消”返回到父状态时转移的牛奶。这样,当您在下一次迭代中尝试使用其他存储桶时,您将拥有一个全新的工作状态,而不会受到以前的递归模拟的污染。

请考虑以下几行:

two.add(x);
one.remove(i);
wednesday(milk - x, one, two);

在执行的这一点上,状态已被永久破坏,这意味着原始状态的存储桶不再匹配其输入,并且循环中的任何进一步的计算都不准确。

相反,请尝试按以下方式恢复状态:

two.add(x);
one.remove(i);
wednesday(milk - x, one, two);
one.add(i, two.remove(two.size()-1)); // undo the milk transfer

使用这种方法,在调用wednesday()之后,牛奶量和存储桶将恢复到它们的原始状态,而以后测试其他存储桶的循环迭代将如此精确地进行。

您也可以在修改它们之前复制这些数组,看起来就像您尝试的那样。这是正确的想法,也可以使用,但是与简单地撤消每个动作并只使用两个列表的效果相比,它的性能要差。

此外,代码可以使用一些重组,这可能有助于理解您的程序状态,减少重复(潜在的错误!)并简化重构。

没有理由在一周中的每一天都有不同的功能,因为每一天都执行相同的步骤,即递归地尝试将每个可用的铲斗运送到另一个储罐。您可以使用day变量表示当天,并在每个递归调用中递增。如果您从第0天开始,则您的递归基本案例是day == 4,此时您可以记录该桶选择序列的最终milk金额。要确定特定日期从哪个谷仓农夫布朗开始,您可以采用day的模数,也可以在每个递归调用中交换源桶和目标桶阵列,并找到一种方法来增加或减少牛奶量,具体取决于您所在的谷仓。

最后,if(!poss.contains(add))是一个线性过程,需要查看列表中的每个元素,并且将对结果计算产生巨大的性能影响。使用HashSet存储可能的唯一结果。此集合的大小是您的最终结果。