从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
。
答案 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
存储可能的唯一结果。此集合的大小是您的最终结果。