简体   繁体   English

只是做了一些练习,遇到了一些问题,不知道是逻辑还是什么。 我需要一双眼睛

[英]Just doing some exercises and ran into some problems, don't know if its logic or what. I need some eyes

I always come back to this problem, I've never solved it.我总是回到这个问题,我从来没有解决过它。 I don't know why it gives me so many problems.我不知道为什么它给我带来了这么多问题。 I usually can get passed the first four test cases fine, then it fails or runs too slow.我通常可以很好地通过前四个测试用例,然后它会失败或运行速度太慢。 Its been almost a year since I took a crack at it, so I decided to give it a fresh look.自从我尝试破解它已经快一年了,所以我决定给它一个新的外观。 I'm not in school, this is just for fun, or at least I thought it would be.我不在学校,这只是为了好玩,或者至少我是这么认为的。 I took a geometrical approach, and used a recursive method.我采用了几何方法,并使用了递归方法。 I'd like to know if anyone can pin point where my logic goes wrong, a test case that would fail the logic.我想知道是否有人可以指出我的逻辑出错的地方,一个会使逻辑失败的测试用例。 Every test case I've come up with on my own seems to be correct when I calculate manually.当我手动计算时,我自己提出的每个测试用例似乎都是正确的。 Unless my math is wrong;除非我的数学错了; I really hope that is not the case.我真的希望不是这样。

So this is the problem: https://open.kattis.com/problems/a1paper所以这就是问题所在: https : //open.kattis.com/problems/a1paper

I'm given 2 lines of input, the first one tells me the lowest number paper size, A2,3,4,5,.... the next line gives me the amount of paper I have starting at size 2, 3, 4, n.我有两行输入,第一行告诉我最小的纸张尺寸,A2,3,4,5,.... 下一行给了我从尺寸 2、3 开始的纸张数量, 4,名词。

The idea is to determine the amount of tape needed to tape the papers together to get an A1 paper.这个想法是确定将纸粘在一起以获得 A1 纸所需的胶带量。

this is my solution:这是我的解决方案:

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;
        }
    }
}

Apparently there exists a testcase this will not work for, Kattis didn't want to give me the test cases, so I'm just curious if anyone has any idea.显然存在一个不适用的测试用例,Kattis 不想给我测试用例,所以我很好奇是否有人有任何想法。 As I stated, every example I've come up with seems to pass.正如我所说,我想出的每个例子似乎都通过了。

I'll explain my function here:我将在这里解释我的功能:

private static Result process(int remainingSizes, double shortSide, double longSide, double remainingArea)

The first call to the function:第一次调用函数:

remainingSizes : the first int received from the input stream.剩余大小:从输入流接收到的第一个 int。 Because it gives you the smallest sized paper, eg.因为它为您提供了最小尺寸的纸张,例如。 4 (A4) , then 3 would be the remaining sizes (A2, A3, A4). 4 (A4) ,那么 3 将是剩余的尺寸 (A2, A3, A4)。

shortSide and longSide for size A2 is given and used to call the function on its first iteration:给出了大小为 A2 的 shortSide 和 longSide 并用于在其第一次迭代时调用函数:

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: when originally passed on the first function call, the Area needed to achieve A1, or double the area of A2.剩余面积:最初传递第一个函数调用时,面积需要达到A1,或A2的面积的两倍。

The two cases that end recursion, either the area is within the absoluteError, or we run out of different sized paper:结束递归的两种情况,要么区域在 absoluteError 之内,要么我们用完了不同大小的纸张:

if (withinAbsoluteError(remainingArea))
            {
                return null;
            }

if (remainingSizes == 0)
                return null;

The next part of the function takes in the amount of A2 sheets (in the first call).函数的下一部分接收 A2 纸的数量(在第一次调用中)。 If we have sheets, then calculate the area of A2, and subtract from the remaining area while keeping count of the sheets used and remaining sheets.如果我们有张数,则计算 A2 的面积,并在保留已用张数和剩余张数的同时从剩余面积中减去。 Then comes the recursive call to the method, cutting the paper in half to obtain the next sized sheet, eg A3.然后递归调用该方法,将纸张切成两半以获得下一个尺寸的纸张,例如 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);

This process will continue until I've met the area or run out of sheets.这个过程将一直持续到我遇到该区域或用完床单。

In the next part of the method is where I determine the amount of tape used:在该方法的下一部分中,我确定使用的磁带量:

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;'

theres two possibilities here, either the previous call returned null, and there were no pages, or there were pages.这里有两种可能性,要么前一次调用返回空值,并且没有页面,要么有页面。 The way I looked at it was, if I'm working back through the function calls, there has to be an even amount of pages as I tape them together and make larger pages.我看待它的方式是,如果我正在处理函数调用,则必须有均匀数量的页面,因为我将它们粘在一起并制作更大的页面。

eg:例如:

If i had 1 - A2, 1 - A3, 2 - A4如果我有 1 - A2, 1 - A3, 2 - A4

then taping the 2 - A4 along their long side, would make an A3, add that to the A3 i have and thats 2 - A3.然后沿着它们的长边粘贴 2 - A4,将制作一个 A3,将其添加到我拥有的 A3 中,那就是 2 - A3。 tape those 2-A3 together makes an A2, add that to the one i have, thats 2-A2.将那些 2-A3 粘在一起制成 A2,将其添加到我拥有的那个,即 2-A2。 And ofcoarse, two A2 makes an A1.而ofcoarse,两个A2组成一个A1。

I dont know if this explination cleared up my code at all, sorry if I made it more confusing than it had to be.我不知道这个解释是否彻底清除了我的代码,对不起,如果我让它比它必须的更混乱。

As pointed out by https://stackoverflow.com/users/1899640/that-other-guy , I was not using the tolerance provided in the question correctly.正如https://stackoverflow.com/users/1899640/that-other-guy所指出的,我没有正确使用问题中提供的容差。

The tolerance given is for the final answer.给出的容差是针对最终答案的。 If you have to sum 0.00001 a million times, the answer needs to be between 9.99999 and 10.00001.如果您必须将 0.00001 相加一百万次,则答案必须介于 9.99999 和 10.00001 之间。 Your code instead says it's ok if the answer is 0, because 0.00001 is within the tolerance so none of the million pieces need to be counted.相反,您的代码表示如果答案为 0 就可以了,因为 0.00001 在容差范围内,因此不需要计算百万件。 This is not sound reasoning.这不是合理的推理。 – that other guy – 另一个人

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM