所有
我一直试图找出如何在一个座位内选择15张票。
编辑:问题是 - 如何查找给定尺寸的所有矩形(例如3x5)的免费座位?
下面是我的表,查询选择4个连续席位(或15个或其他),这很好......
但我想要做的是选择15个座位,这些座位可以分成多行,即3 x 5,但我希望它们能够被封锁在一起,即
row 9 ..(some seats)..[5 seats]..(some seats)..
row 8 ..(some seats)..[5 seats]..(some seats)..
row 7 ..(some seats)..[5 seats]..(some seats)..
即。它们将在彼此前面排成3排。 row9座位10到25,row8座位10到25,row7座位10到25。
也可能需要考虑一个座位是否有不同数量的座位,即角块可能呈弧形,后面的座位比前面的座位多。
任何形式的指导,包括SQL或某些算法或某些PHP代码。一周的大部分时间里,我一直在捣乱我的大脑。
CREATE TABLE `seats` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`event_id` int(11) DEFAULT NULL,
`performance` int(11) DEFAULT NULL,
`block` int(11) DEFAULT NULL,
`row` int(11) DEFAULT NULL,
`seat` int(11) DEFAULT NULL,
`status` int(10) DEFAULT 1,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
我的查询到目前为止 - 它返回X席位的组合。
SELECT a.event_id, a.performance, a.block,
a.row, a.seat AS start_seat,
a.seat + (4 - 1) AS end_seat,
4 AS requested_seats,
a.id AS start_allocation_id
FROM seats a
LEFT JOIN seats b ON
a.event_id = b.event_id AND
a.performance = b.performance AND
a.block = b.block AND
a.row = b.row AND
a.seat < b.seat AND
b.seat < a.seat + 4 AND
b.status = 1
WHERE a.status = 1 AND
a.event_id = 1
GROUP BY a.seat
HAVING COUNT(b.seat) + 1 = 4
ORDER BY performance
提前致谢,需要更多信息,请直接询问!
答案 0 :(得分:13)
在mysql之外用另一种语言解决这个问题要好得多。换句话说,你有一个座位矩阵,其中一些是被占用的(灰色的):
并且你想找到给定尺寸的所有矩形,比如3x5。您可以通过两次线性O(n)
时间算法(n为席位数)非常有效地执行此操作:
1)在第一次传递中,按列从下到上,每个座位,表示可用的连续座位数:
重复,直到:
2)在第二次传递中,按行,查找至少5个连续数字大于或等于3:
所以,最后,你得到:
产生解决方案:这些数字序列(绿色区域)是2个可能的3 * 5个自由座位矩形的顶部边缘。
该算法可以很容易地增强到例如得到最大面积的所有矩形。或者,它可用于查找N个座位的任何连续区域(不仅是矩形) - 只是在第二次通过期间,查找连续的数字序列,总计至少为N.
答案 1 :(得分:3)
根据您的描述,这不是数据库问题,而是算法问题。我建议平铺模式可能是四叉树或空间填充曲线。也许MySQL中的空间索引也可以帮助您解决问题。 A si将2d平面细分为4个瓦片。
答案 2 :(得分:1)
我来到这里寻找Python解决方案。这是我的,它返回所有位置:
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)
输出:
area 15 row 4 col 8 height 3 width 5
area 15 row 5 col 10 height 3 width 5
答案 3 :(得分:0)
$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 :)
答案 4 :(得分:0)
如果您可以通过编程方式创建查询,我只会为每一行编写一个查询并使用UNION
进行组合,然后只需使用相同的查询X次,只需使用UNION
附加它们即可。
UNION用于组合多个SELECT语句的结果 到一个结果集。
答案 5 :(得分:0)
首先,我假设大多数场地可以映射(即使近似)到方格,即。座位没有奇怪的设置或奇怪的抵消。因此,每个座位周围最多可有八个座位。
CREATE TABLE Seat {
SeatID int,
Status int,
...
NorthID int,
NorthWestID int,
WestID int,
...
NorthEastID int
}
基本上,我将能够创建一个“座位图”并根据查询需要进行操作。然后,您可以创建查询以获取某些形状或块。
3x3网格将包括选择一个开放的座位,其中所有方向的直接链接座位也是开放的。是的,这将是八个JOINS,但是试试看并稍后进行优化。
SELECT * FROM Seat x
INNER JOIN Seat n ON x.NorthID = n.SeatID
INNER JOIN Seat nw ON x.NorthWestID = n.SeatID
...
1x15区块将是一个选择开放式座位的查询,您可以沿着EastID或WestID加入14个深处。
您可以以编程方式概括和生成查询。
PS:根据您使用的引擎,您可能具有内置的空间功能。
祝你好运。答案 6 :(得分:0)
这是一种直截了当的方法。它可能不足以满足您的需求,但它是一个可以开始的地方。
让我们简化问题,并考虑一个名为seat
的表,其中包含row
,col
和taken
列。前两个是整数,另一个是布尔值。我们希望找到row
和col
的值约束到某些大小的矩形,其中taken
通常是假的。我们将尝试一个查询,该查询移动一个矩形并记录其中taken
值的总和。我们想要的矩形的总和为零。
我们只是说我们正在寻找2x2的开放式座位。这是查询。
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
只需过滤此查询的输出count = 0
。 row
和col
将指定打开块的左上角。最后一个怪癖是,您需要过滤掉靠近座位右侧或底部边缘的左上角,因为这会人为地减少它们的总和(被测试的矩形被裁剪到座位的边缘)。对于2x2块,这意味着row < max(row)
和col < max(col)
。
现在,在找到15个相邻座位的情况下,您正在寻找15x1,1x15,3x5和5x3矩形。您可以将上述查询转换为采用矩形宽度和高度参数的存储过程,然后使用这些大小调用它,直到找到匹配项。