如何在1-80数字矩阵中生成不重叠的x组y个块状数字(Delphi)
Delphi实现8x10矩阵生成不重叠2x2数字块方案(x=2,y=4)
核心逻辑梳理
1. 数字与矩阵坐标映射
针对1-80的8行10列矩阵,采用0-based坐标(行r:0~7,列c:0~9)实现双向转换:
- 数字转坐标:
r := (n - 1) div 10; c := (n - 1) mod 10; - 坐标转数字:
n := r * 10 + c + 1;
2. 2x2块的有效范围
2x2块的起始坐标(r,c)必须满足:
- 行方向:
r + 1 < 8→ r ∈ 0~6 - 列方向:
c + 1 < 10→ c ∈ 0~8
总计7×9=63个有效2x2块,每个块包含的4个数字对应坐标:(r,c)、(r,c+1)、(r+1,c)、(r+1,c+1)。
3. 块重叠判断规则
两个块A(rA,cA)和B(rB,cB)不重叠的条件是:行范围无交集 或 列范围无交集,代码逻辑:
function IsBlocksNonOverlap(const A, B: TBlock): Boolean; begin Result := (A.r + 1 < B.r) or (B.r + 1 < A.r) or (A.c + 1 < B.c) or (B.c + 1 < A.c); end;
高效编码实现
1. 定义数据结构
type TBlock = record r, c: Integer; // 2x2块的起始坐标(0-based) Numbers: array[0..3] of Integer; // 块包含的4个数字 end;
2. 生成单个有效2x2块
function GenerateSingleBlock: TBlock; var r, c: Integer; begin // 随机生成有效起始坐标 r := Random(7); c := Random(9); // 填充块内数字 Result.r := r; Result.c := c; Result.Numbers[0] := r * 10 + c + 1; Result.Numbers[1] := r * 10 + (c + 1) + 1; Result.Numbers[2] := (r + 1) * 10 + c + 1; Result.Numbers[3] := (r + 1) * 10 + (c + 1) + 1; end;
3. 生成x个不重叠块(以x=2为例)
function GenerateNonOverlapBlocks(const Count: Integer): TArray<TBlock>; var i, j: Integer; CurrentBlock: TBlock; IsValid: Boolean; begin SetLength(Result, Count); // 生成第一个块 Result[0] := GenerateSingleBlock; // 生成后续块,确保与已有块不重叠 for i := 1 to Count - 1 do begin repeat CurrentBlock := GenerateSingleBlock; IsValid := True; for j := 0 to i - 1 do begin if not IsBlocksNonOverlap(Result[j], CurrentBlock) then begin IsValid := False; Break; end; end; until IsValid; Result[i] := CurrentBlock; end; end;
4. 使用示例
procedure TForm1.Button1Click(Sender: TObject); var Blocks: TArray<TBlock>; i: Integer; begin Randomize; Blocks := GenerateNonOverlapBlocks(2); // 输出结果到Memo for i := 0 to High(Blocks) do begin Memo1.Lines.Add(Format('第%d组数字: %d, %d, %d, %d', [i+1, Blocks[i].Numbers[0], Blocks[i].Numbers[1], Blocks[i].Numbers[2], Blocks[i].Numbers[3]])); end; end;
优化方案(针对大x场景)
当需要生成的组数较多时,可预先生成所有有效块列表,每次选块后从列表中移除所有重叠的块,后续直接从剩余列表随机选择,避免重复判断。也可采用位掩码记录已占用数字,提升重叠判断效率:
type TBitMask = array[0..1] of UInt64; // 前64位存1-64,后16位存65-80 function IsBlockAvailable(const Mask: TBitMask; const Block: TBlock): Boolean; var n, idx, bit: Integer; begin Result := True; for n in Block.Numbers do begin idx := (n - 1) div 64; bit := (n - 1) mod 64; if (Mask[idx] and (1 shl bit)) <> 0 then begin Result := False; Break; end; end; end;
内容的提问来源于stack exchange,提问作者Daniel Hobson
相关产品推荐
相关产品推荐

