只是做一些习题和 运行 做一些问题,不知道它的逻辑还是什么。我需要一些眼睛
Just doing some exercises and ran into some problems, don't know if its logic or what. I need some eyes
我总是回到这个问题,我从来没有解决过。我不知道为什么它给我这么多问题。我通常可以很好地通过前四个测试用例,然后失败或 运行s 太慢了。我开始尝试它已经将近一年了,所以我决定给它一个新的面貌。我不在学校,这只是为了好玩,或者至少我认为是这样。我采用了几何方法,并使用了递归方法。我想知道是否有人可以指出我的逻辑出错的地方,一个会使逻辑失败的测试用例。当我手动计算时,我自己想出的每个测试用例似乎都是正确的。除非我的数学错了;我真的希望不是这样。
这就是问题所在:https://open.kattis.com/problems/a1paper
我有两行输入,第一行告诉我最小的纸张尺寸,A2,3,4,5,....下一行告诉我我的起始纸张数量尺码 2, 3, 4, n.
想法是确定将纸张粘在一起以获得 A1 纸所需的胶带量。
这是我的解决方案:
import java.util.Scanner;
public class A1Paper
{
private static Scanner scan = new Scanner(System.in);
private static final double ABSOLUTE_ERROR = Math.pow(10.0, -5.0);
public static void main(String[] args)
{
final double SHORT_SIDE = Math.pow(2.0, -5.0/4.0);
final double LONG_SIDE = Math.pow(2.0, -3.0/4.0);
final double A1_AREA = 2 * SHORT_SIDE * LONG_SIDE;
int remainingSizes = scan.nextInt() - 1;
scan.nextLine();
Result result = process(remainingSizes, SHORT_SIDE, LONG_SIDE, A1_AREA);
if (result != null)
System.out.println(result.getTape());
else
System.out.println("impossible");
scan.close();
return;
}
private static Result process(int remainingSizes, double shortSide, double longSide, double remainingArea)
{
if (withinAbsoluteError(remainingArea))
{
return null;
}
if (remainingSizes == 0)
return null;
int remainingSheets = scan.nextInt();
int sheetsUsed = 0;
if (remainingSheets > 0)
{
double sheetArea = shortSide * longSide;
while (remainingSheets > 0 && !withinAbsoluteError(remainingArea))
{
remainingSheets--;
sheetsUsed++;
remainingArea -= sheetArea;
}
}
Result prevResult = process(remainingSizes - 1, longSide/2.0, shortSide, remainingArea);
Result thisResult = null;
if (prevResult == null)
{
if (sheetsUsed%2 != 0 || sheetsUsed == 0)
return null;
thisResult = new Result(sheetsUsed/2, sheetsUsed/2 * longSide);
}
else
{
sheetsUsed += prevResult.getSheets();
if (sheetsUsed%2 !=0)
return null;
thisResult = new Result(sheetsUsed/2, prevResult.getTape() + (sheetsUsed/2 * longSide));
}
return thisResult;
}
private static boolean withinAbsoluteError(double remainingArea)
{
if (remainingArea <= ABSOLUTE_ERROR && remainingArea >= -ABSOLUTE_ERROR)
return true;
else
return false;
}
private static class Result
{
private int sheets;
private double tape;
public Result(int sheets, double tape)
{
this.sheets = sheets;
this.tape = tape;
}
public int getSheets()
{
return sheets;
}
public double getTape()
{
return tape;
}
}
}
显然存在一个无法使用的测试用例,Kattis 不想给我测试用例,所以我很好奇是否有人知道。正如我所说,我想出的每个例子似乎都通过了。
我将在这里解释我的功能:
private static Result process(int remainingSizes, double shortSide, double longSide, double remainingArea)
第一次调用函数:
remainingSizes :从输入流接收到的第一个 int。因为它给你最小尺寸的纸张,例如。 4 (A4) ,那么 3 就是剩余的尺寸 (A2, A3, A4)。
给出了大小为 A2 的短边和长边,并用于在第一次迭代时调用该函数:
final double SHORT_SIDE = Math.pow(2.0, -5.0/4.0);
final double LONG_SIDE = Math.pow(2.0, -3.0/4.0);
remainingArea: 最初传递给第一个函数调用时,需要达到A1的Area,或者是A2面积的两倍。
结束递归的两种情况,要么是在absoluteError范围内,要么是我们运行出了不同大小的纸张:
if (withinAbsoluteError(remainingArea))
{
return null;
}
if (remainingSizes == 0)
return null;
函数的下一部分接受 A2 sheets 的数量(在第一次调用中)。如果我们有 sheets,则计算 A2 的面积,并从剩余面积中减去,同时保持使用的 sheets 和剩余的 sheets 的计数。然后是对该方法的递归调用,将纸张切成两半以获得下一个尺寸 sheet,例如 A3.
int remainingSheets = scan.nextInt();
int sheetsUsed = 0;
if (remainingSheets > 0)
{
double sheetArea = shortSide * longSide;
while (remainingSheets > 0 && !withinAbsoluteError(remainingArea))
{
remainingSheets--;
sheetsUsed++;
remainingArea -= sheetArea;
}
}
Result prevResult = process(remainingSizes - 1, longSide/2.0, shortSide, remainingArea);
此过程将继续,直到我遇到该区域或 sheet 中的 运行。
在该方法的下一部分中,我确定使用的磁带量:
Result thisResult = null;
if (prevResult == null)
{
if (sheetsUsed%2 != 0 || sheetsUsed == 0)
return null;
thisResult = new Result(sheetsUsed/2, sheetsUsed/2 * longSide);
}
else
{
sheetsUsed += prevResult.getSheets();
if (sheetsUsed%2 !=0)
return null;
thisResult = new Result(sheetsUsed/2, prevResult.getTape() + (sheetsUsed/2 * longSide));
}
return thisResult;'
这里有两种可能,要么之前的调用返回null,没有页面,要么有页面。我的看法是,如果我通过函数调用返回,则必须有均匀数量的页面,因为我将它们粘在一起并制作更大的页面。
例如:
如果我有 1 - A2, 1 - A3, 2 - A4
然后将 2 - A4 沿其长边粘贴,将制作 A3,将其添加到我拥有的 A3 中,这就是 2 - A3。把那些 2-A3 粘在一起做成一个 A2,把它加到我有的那个上,那就是 2-A2。粗略地说,两个 A2 就是一个 A1。
我不知道这个解释是否完全清除了我的代码,抱歉,如果我让它变得比它必须的更混乱。
正如https://whosebug.com/users/1899640/that-other-guy所指出的,我没有正确使用问题中提供的公差。
给出的容差是最终答案。如果您必须对 0.00001 求和一百万次,则答案需要介于 9.99999 和 10.00001 之间。相反,您的代码表示如果答案为 0 也没关系,因为 0.00001 在容差范围内,因此需要对百万件中的 none 进行计数。这不是合理的推理。 – 那个人
我总是回到这个问题,我从来没有解决过。我不知道为什么它给我这么多问题。我通常可以很好地通过前四个测试用例,然后失败或 运行s 太慢了。我开始尝试它已经将近一年了,所以我决定给它一个新的面貌。我不在学校,这只是为了好玩,或者至少我认为是这样。我采用了几何方法,并使用了递归方法。我想知道是否有人可以指出我的逻辑出错的地方,一个会使逻辑失败的测试用例。当我手动计算时,我自己想出的每个测试用例似乎都是正确的。除非我的数学错了;我真的希望不是这样。
这就是问题所在:https://open.kattis.com/problems/a1paper
我有两行输入,第一行告诉我最小的纸张尺寸,A2,3,4,5,....下一行告诉我我的起始纸张数量尺码 2, 3, 4, n.
想法是确定将纸张粘在一起以获得 A1 纸所需的胶带量。
这是我的解决方案:
import java.util.Scanner;
public class A1Paper
{
private static Scanner scan = new Scanner(System.in);
private static final double ABSOLUTE_ERROR = Math.pow(10.0, -5.0);
public static void main(String[] args)
{
final double SHORT_SIDE = Math.pow(2.0, -5.0/4.0);
final double LONG_SIDE = Math.pow(2.0, -3.0/4.0);
final double A1_AREA = 2 * SHORT_SIDE * LONG_SIDE;
int remainingSizes = scan.nextInt() - 1;
scan.nextLine();
Result result = process(remainingSizes, SHORT_SIDE, LONG_SIDE, A1_AREA);
if (result != null)
System.out.println(result.getTape());
else
System.out.println("impossible");
scan.close();
return;
}
private static Result process(int remainingSizes, double shortSide, double longSide, double remainingArea)
{
if (withinAbsoluteError(remainingArea))
{
return null;
}
if (remainingSizes == 0)
return null;
int remainingSheets = scan.nextInt();
int sheetsUsed = 0;
if (remainingSheets > 0)
{
double sheetArea = shortSide * longSide;
while (remainingSheets > 0 && !withinAbsoluteError(remainingArea))
{
remainingSheets--;
sheetsUsed++;
remainingArea -= sheetArea;
}
}
Result prevResult = process(remainingSizes - 1, longSide/2.0, shortSide, remainingArea);
Result thisResult = null;
if (prevResult == null)
{
if (sheetsUsed%2 != 0 || sheetsUsed == 0)
return null;
thisResult = new Result(sheetsUsed/2, sheetsUsed/2 * longSide);
}
else
{
sheetsUsed += prevResult.getSheets();
if (sheetsUsed%2 !=0)
return null;
thisResult = new Result(sheetsUsed/2, prevResult.getTape() + (sheetsUsed/2 * longSide));
}
return thisResult;
}
private static boolean withinAbsoluteError(double remainingArea)
{
if (remainingArea <= ABSOLUTE_ERROR && remainingArea >= -ABSOLUTE_ERROR)
return true;
else
return false;
}
private static class Result
{
private int sheets;
private double tape;
public Result(int sheets, double tape)
{
this.sheets = sheets;
this.tape = tape;
}
public int getSheets()
{
return sheets;
}
public double getTape()
{
return tape;
}
}
}
显然存在一个无法使用的测试用例,Kattis 不想给我测试用例,所以我很好奇是否有人知道。正如我所说,我想出的每个例子似乎都通过了。
我将在这里解释我的功能:
private static Result process(int remainingSizes, double shortSide, double longSide, double remainingArea)
第一次调用函数:
remainingSizes :从输入流接收到的第一个 int。因为它给你最小尺寸的纸张,例如。 4 (A4) ,那么 3 就是剩余的尺寸 (A2, A3, A4)。
给出了大小为 A2 的短边和长边,并用于在第一次迭代时调用该函数:
final double SHORT_SIDE = Math.pow(2.0, -5.0/4.0);
final double LONG_SIDE = Math.pow(2.0, -3.0/4.0);
remainingArea: 最初传递给第一个函数调用时,需要达到A1的Area,或者是A2面积的两倍。
结束递归的两种情况,要么是在absoluteError范围内,要么是我们运行出了不同大小的纸张:
if (withinAbsoluteError(remainingArea))
{
return null;
}
if (remainingSizes == 0)
return null;
函数的下一部分接受 A2 sheets 的数量(在第一次调用中)。如果我们有 sheets,则计算 A2 的面积,并从剩余面积中减去,同时保持使用的 sheets 和剩余的 sheets 的计数。然后是对该方法的递归调用,将纸张切成两半以获得下一个尺寸 sheet,例如 A3.
int remainingSheets = scan.nextInt();
int sheetsUsed = 0;
if (remainingSheets > 0)
{
double sheetArea = shortSide * longSide;
while (remainingSheets > 0 && !withinAbsoluteError(remainingArea))
{
remainingSheets--;
sheetsUsed++;
remainingArea -= sheetArea;
}
}
Result prevResult = process(remainingSizes - 1, longSide/2.0, shortSide, remainingArea);
此过程将继续,直到我遇到该区域或 sheet 中的 运行。
在该方法的下一部分中,我确定使用的磁带量:
Result thisResult = null;
if (prevResult == null)
{
if (sheetsUsed%2 != 0 || sheetsUsed == 0)
return null;
thisResult = new Result(sheetsUsed/2, sheetsUsed/2 * longSide);
}
else
{
sheetsUsed += prevResult.getSheets();
if (sheetsUsed%2 !=0)
return null;
thisResult = new Result(sheetsUsed/2, prevResult.getTape() + (sheetsUsed/2 * longSide));
}
return thisResult;'
这里有两种可能,要么之前的调用返回null,没有页面,要么有页面。我的看法是,如果我通过函数调用返回,则必须有均匀数量的页面,因为我将它们粘在一起并制作更大的页面。
例如:
如果我有 1 - A2, 1 - A3, 2 - A4
然后将 2 - A4 沿其长边粘贴,将制作 A3,将其添加到我拥有的 A3 中,这就是 2 - A3。把那些 2-A3 粘在一起做成一个 A2,把它加到我有的那个上,那就是 2-A2。粗略地说,两个 A2 就是一个 A1。
我不知道这个解释是否完全清除了我的代码,抱歉,如果我让它变得比它必须的更混乱。
正如https://whosebug.com/users/1899640/that-other-guy所指出的,我没有正确使用问题中提供的公差。
给出的容差是最终答案。如果您必须对 0.00001 求和一百万次,则答案需要介于 9.99999 和 10.00001 之间。相反,您的代码表示如果答案为 0 也没关系,因为 0.00001 在容差范围内,因此需要对百万件中的 none 进行计数。这不是合理的推理。 – 那个人