【问题标题】:Incorrect Ouput for USACO December 2018 Bronze Back ForthUSACO 2018 年 12 月铜牌的错误输出
【发布时间】:2019-01-19 17:22:42
【问题描述】:

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

【问题讨论】:

  • 如果 cooyright 允许,最好在问题中包含问题陈述。我们可以很懒惰地点击这里的链接。此外,当我们试图让 Stack Overflow 成为持久的知识资源时,链接往往会随着时间的推移而失效。
  • 在我的脑海中,问题描述说:“周一,Farmer John 测量了第一个谷仓的罐中正好 1000 加仑的牛奶,而第一个谷仓的罐中正好测量了 1000 加仑的牛奶。第二个谷仓。”我会更仔细地考虑该想法是否以及如何应用于代码尝试模拟不同场景(在所有函数中,而不仅仅是tuesday。)在我看来,for 循环中的迭代可能对意外版本起作用onetwo。例如,尝试在 tuesday for 循环中的每次迭代开始时记录它们。

标签: java algorithm


【解决方案1】:

您的方法非常正确,将其表述为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 数量。要确定给定日期 Farmer Brown 从哪个谷仓开始,您可以取 day 的模数,或者在每次递归调用时交换源和目标存储桶数组,并找到一种方法来添加或减去牛奶量,具体取决于哪个你所在的谷仓。

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

【讨论】:

    猜你喜欢
    • 2021-11-03
    • 1970-01-01
    • 2021-10-29
    • 2023-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多