Max square size for unknown number inside rectangle

前端 未结 10 530
陌清茗
陌清茗 2020-12-03 07:58

If I have a set of tiles (squares) which can be any number and they are to fill a container (rectangle) of an unknown size how do I work out the maximum size of the tiles wi

10条回答
  •  情话喂你
    2020-12-03 08:35

    Here is an O(1) solution with no loops.

    Using the aspect ratio (height/width) of the rectangle, you can come up with an initial guess at the number of tiles in the x and y directions. This gives an upper and lower bound for the total number of tiles: between xy and (x+1)(y+1).

    Based on these bounds, there are three possibilities:

    1. The lower bound is correct. Compute the largest tileSize that will result in xy tiles.
    2. The upper bound is correct. Compute the largest tileSize that will result in (x+1)(y+1) tiles
    3. The correct answer lies somewhere between the upper and lower bounds. Solve an equation to determine the correct values of x and y, and then compute the largest tileSize that will result in the correct number of tiles
    int GetTileSize(int width, int height, int tileCount)
    {
        // quick bailout for invalid input
        if (width*height < tileCount) { return 0; }
    
        // come up with an initial guess
        double aspect = (double)height/width;
        double xf = sqrtf(tileCount/aspect);
        double yf = xf*aspect;
        int x = max(1.0, floor(xf));
        int y = max(1.0, floor(yf));
        int x_size = floor((double)width/x);
        int y_size = floor((double)height/y);
        int tileSize = min(x_size, y_size);
    
        // test our guess:
        x = floor((double)width/tileSize);
        y = floor((double)height/tileSize);
        if (x*y < tileCount) // we guessed too high
        {
            if (((x+1)*y < tileCount) && (x*(y+1) < tileCount))
            {
                // case 2: the upper bound is correct
                //         compute the tileSize that will
                //         result in (x+1)*(y+1) tiles
                x_size = floor((double)width/(x+1));
                y_size = floor((double)height/(y+1));
                tileSize = min(x_size, y_size);
            }
            else
            {
                // case 3: solve an equation to determine
                //         the final x and y dimensions
                //         and then compute the tileSize
                //         that results in those dimensions
                int test_x = ceil((double)tileCount/y);
                int test_y = ceil((double)tileCount/x);
                x_size = min(floor((double)width/test_x), floor((double)height/y));
                y_size = min(floor((double)width/x), floor((double)height/test_y));
                tileSize = max(x_size, y_size);
            }
        }
    
        return tileSize;
    }
    

    I have tested this function for all integer widths, heights and tileCounts between 1 and 1000 using the following code:

    for (width = 1 to 1000)
    {
        for (height = 1 to 1000)
        {
            for (tileCount = 1 to 1000)
            {
                tileSize = GetTileSize(width, height, tileCount);
    
                // verify that increasing the tileSize by one
                // will result in too few tiles
                x = floor((double)width/(tileSize+1));
                y = floor((double)height/(tileSize+1));
                assert(x*y < tileCount);
    
                // verify that the computed tileSize actually
                // results in the correct tileCount
                if (tileSize > 0)
                {
                    x = floor((double)width/tileSize);
                    y = floor((double)height/tileSize);
                    assert(x*y >= tileCount);
                }
            }
        }
    }
    

提交回复
热议问题