Search matrix for all rectangles of given dimensions (select blocks of seats)

前端 未结 7 441
忘了有多久
忘了有多久 2020-12-08 11:46

All,

I have been trying to work out how to select say 15 tickets within a single block of seats.

EDIT: the problem is - how to find all rect

相关标签:
7条回答
  • 2020-12-08 11:59

    Here is a straightforward approach. It may not be fast enough for your needs, but it is a place to start.

    Let's simplify the problem and consider a table called seat having columns row, col, and taken. The first two are integers, the other is a boolean. We want to find values of row and col constrained to certain sized rectangles wherein taken is universally false. We'll try a query which moves a rectangle around and records the sum of the taken values within. The rectangles we want will have a sum of zero.

    Let's just say we're looking for 2x2 blocks of open seats. Here's the query.

    SELECT row, col,
           (select sum(taken) from seat as s2
                   where s2.row >= s1.row and s2.row < s1.row + 2
                     and s2.col >= s1.col and s2.col < s1.col + 2) as count
           FROM seat as s1
    

    Just filter the output of this query where count = 0. The row and col will designate the upper left corner of the open block. One final quirk is that you will want to filter out upper left corners that cut too close to the right or bottom edges of the seating, because that will artificially decrease their sum (the tested rectangle is clipped against the edges of the seating). In the case of 2x2 blocks, this means row < max(row) and col < max(col).

    Now in the case of finding 15 adjacent seats, you are looking for 15x1, 1x15, 3x5 and 5x3 rectangles. You could make the above query into a stored procedure that takes rectangle width and height parameters, and then call it with those sizes until you find a match.

    0 讨论(0)
  • 2020-12-08 12:00
        $nr_tickets = 15; // or whatever
    
    
    // build an array of different configurations:
    // since you always want people as close to eachother as possible this is a suggestion:
    
    $configurations = array();
    for($columns=1; $columns<=$nr_tickets; $columns++)
    {
        $BLOCK = array();
        $remainder = $nr_tickets % $columns;
        // $nr_tickets - $remainder = greatest number divisible exactly by $i (columns) which is the number of rows you want.
        $rows = (($nr_ticket-$odd) / $i);
        //$configurations[$columns] = $rows // make a rectangle configuration or $columns x $rows with $remainder tickets left.
        $BLOCK[] = array_fill(0, $columns, array_fill(0, $rows, X); // multidimensional array
        for($a=0; $a<$odd; $a++)
        {
    
            // each of the remainder seats need to be 'stuck on to the block/rectangle of seats you already have, this can be done in
            // ($rows + $columns * 2) - $a ways for each of the consecutive non-assigned tickets
            /*
                lets say you have a block of 2x7 (s) with 1 (N) possible ticket left 
                       N  N  N  N  N  N  N  
                N  s  s  s  s  s  s  s  N 
                N  s  s  s  s  s  s  s  N   
                   N  N  N  N  N  N  N 
            */
            // so basically we can add a ticket to each of the rows and for each of those configurations we need to add $a more
            // this may be simpler with a recursive function call that adds $a more for each 1 ticket you add here to a row or a column. 
        }
    
    
    }
    
    
    
    // now you can go select all different permutations of settings from the database and select one you like :) 
    
    0 讨论(0)
  • 2020-12-08 12:00

    First, I'm going to assume that most venues can be mapped (even if approximated) to a square grid, ie. where the seats aren't strangely setup or weirdly offset. As such, each seat may have up to eight seats around it.

    CREATE TABLE Seat {
       SeatID int,
       Status int,
       ...
       NorthID int,
       NorthWestID int,
       WestID int,
       ...
       NorthEastID int
    }
    

    Essentially, I will be able to create a "seat graph" and walk it according to needs in querying. Then, you can create queries to get certain shapes or blocks.

    A 3x3 grid would consist of selecting an open seat where the immediate linked seats in all directions are also open. Yes, it would be eight JOINS, but try it out and optimize later.

    SELECT * FROM Seat x
    INNER JOIN Seat n ON x.NorthID = n.SeatID
    INNER JOIN Seat nw ON x.NorthWestID = n.SeatID
    ...
    

    A 1x15 block would be a query to select an open seat where you join 14 deep along the EastID or WestID.

    You can probably generalize and generate the queries programatically.

    PS: Depending on which engine you are using, you may have built-in spatial capabilities.

    Good luck.

    0 讨论(0)
  • 2020-12-08 12:07

    I would just write a query for each row and combine it using UNION if you can programmatically create your query, then just use the same query X number of times just keep appending them with UNION.

    From the mysql manual

    UNION is used to combine the result from multiple SELECT statements into a single result set.

    0 讨论(0)
  • 2020-12-08 12:18

    From your description this isn't a database problem but an algorithmic problem. I suggest a tiling schema maybe a quadtree or a space-filling-curve. Perhaps a spatial-index in MySQL would help you solve your problem, too. A si subdivide the 2d plane into 4 tiles.

    0 讨论(0)
  • 2020-12-08 12:22

    I came here looking for a Python solution. Here is mine, which returns all positions:

    import numpy
    
    s = '''0 0 0 0 1 0 0 0 1 0 0
    0 0 0 0 0 0 1 0 1 0 1
    0 1 0 0 0 0 0 0 0 1 0
    0 0 0 0 0 0 0 0 0 0 0
    0 0 1 1 0 0 0 0 0 0 0
    0 0 0 0 0 1 0 0 0 0 0'''
    
    area = 15
    nrows = 6
    ncols = 11
    skip = 1
    
    a = numpy.fromstring(s, dtype=int, sep=' ').reshape(nrows, ncols)
    w = numpy.zeros(dtype=int, shape=a.shape)
    h = numpy.zeros(dtype=int, shape=a.shape)
    for r in range(nrows):
        for c in range(ncols):
            if a[r][c] == skip:
                continue
            if r == 0:
                h[r][c] = 1
            else:
                h[r][c] = h[r-1][c]+1
            if c == 0:
                w[r][c] = 1
            else:
                w[r][c] = w[r][c-1]+1
            minw = w[r][c]
            for dh in range(h[r][c]):
                minw = min(minw, w[r-dh][c])
                if (dh+1)*minw == area:
                    print(
                        'area', area, 'row', r, 'col', c,
                        'height', dh+1, 'width', minw)
    

    Output:

    area 15 row 4 col 8 height 3 width 5
    area 15 row 5 col 10 height 3 width 5
    
    0 讨论(0)
提交回复
热议问题