2025年12月17日,小米mimoAI工具发布了,赶紧试用一下。
编写用DLX求解方块组成的不同形状(类似俄罗斯方块)精确覆盖矩形问题C程序,参数,矩形宽度、高度,[形状,个数]列表。输出代表形状的字母填充的矩阵。比如A是1x1方块,B是1x2方块,求解"4,4,[A,4,B,6]",返回:
B B B B
B B B B
B B B A
A A B A
他深度思考了259秒,给出了如下程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
// ---------- 数据结构定义 ----------
typedef struct Point {
int x, y;
} Point;
typedef struct {
char letter;
int count;
} ShapeItem; // 输入的形状项
typedef struct {
char letter;
Point *offsets; // 基础偏移(某个朝向)
int num_cells;
} ShapeBase; // 形状库基础定义
typedef struct {
Point *points; // 规范化后的点集(平移至原点)
int num_points;
int width, height;
} Rotation; // 一个旋转后的形状
typedef struct {
char letter;
Rotation *rotations;
int num_rotations;
} ShapeInfo; // 形状的完整旋转信息
// DLX 节点结构
typedef struct Node {
struct Node *left, *right, *up, *down;
struct Node *col; // 指向列头节点
int rowid; // 行ID,-1 表示列头
int size; // 仅列头有效:该列节点数
} Node;
// ---------- 全局变量 ----------
int W, H;
int total_cols;
ShapeItem *input_shapes;
int input_shape_count;
ShapeInfo *shapes_info;
int *shape_remaining; // 每种形状剩余数量
int *row_to_shape; // 行ID -> 形状索引
Node **row_first_nodes; // 行ID -> 该行任意节点
int total_rows;
int *solution_rows; // 存储解的行ID
int depth; // 当前搜索深度
Node *header; // DLX 头节点
Node *col_headers; // 列头数组
// ---------- 形状库基础定义 ----------
ShapeBase shape_bases[] = {
{'A', (Point[]){{0,0}}, 1},
{'B', (Point[]){{0,0},{1,0}}, 2},
// 可在此添加更多形状,例如:
// {'C', (Point[]){{0,0},{1,0},{2,0}}, 3},
// {'D', (Point[]){{0,0},{1,0},{0,1},{1,1}}, 4},
// {'E', (Point[]){{0,0},{1,0},{0,1}}, 3}, // L 形
{0, NULL, 0}
};
// ---------- 辅助函数 ----------
ShapeBase *find_shape_base(char letter) {
for (int i = 0; shape_bases[i].letter != 0; i++) {
if (shape_bases[i].letter == letter)
return &shape_bases[i];
}
return NULL;
}
// 旋转点集
void rotate_points(Point *in, int n, int rot, Point *out) {
for (int i = 0; i < n; i++) {
int x = in[i].x, y = in[i].y;
switch (rot) {
case 0: out[i].x = x; out[i].y = y; break; // 0°
case 1: out[i].x = -y; out[i].y = x; break; // 90°
case 2: out[i].x = -x; out[i].y = -y; break; // 180°
case 3: out[i].x = y; out[i].y = -x; break; // 270°
}
}
}
// 规范化点集(平移使 min_x = min_y = 0),并返回尺寸
void normalize_points(Point *pts, int n, int *min_x, int *min_y, int *max_x, int *max_y) {
int mx = pts[0].x, my = pts[0].y;
int Mx = pts[0].x, My = pts[0].y;
for (int i = 1; i < n; i++) {
if (pts[i].x < mx) mx = pts[i].x;
if (pts[i].y < my) my = pts[i].y;
if (pts[i].x > Mx) Mx = pts[i].x;
if (pts[i].y > My) My = pts[i].y;
}
for (int i = 0; i < n; i++) {
pts[i].x -= mx;
pts[i].y -= my;
}
*min_x = 0; *min_y = 0;
*max_x = Mx - mx;
*max_y = My - my;
}
// 点集排序(简单冒泡,点数极少)
void sort_points(Point *pts, int n) {
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n-i-1; j++) {
if (pts[j].x > pts[j+1].x || (pts[j].x == pts[j+1].x && pts[j].y > pts[j+1].y)) {
Point tmp = pts[j];
pts[j] = pts[j+1];
pts[j+1] = tmp;
}
}
}
}
// 比较两个点集是否相同(假设已排序)
bool points_equal(Point *a, Point *b, int n) {
for (int i = 0; i < n; i++)
if (a[i].x != b[i].x || a[i].y != b[i].y) return false;
return true;
}
// 生成形状的旋转信息
ShapeInfo generate_shape_info(ShapeBase *base) {
ShapeInfo info;
info.letter = base->letter;
info.num_rotations = 0;
info.rotations = malloc(4 * sizeof(Rotation)); // 最多4个旋转
for (int rot = 0; rot < 4; rot++) {
Point temp_pts[4]; // 最多4格
rotate_points(base->offsets, base->num_cells, rot, temp_pts);
// 规范化
int min_x, min_y, max_x, max_y;
normalize_points(temp_pts, base->num_cells, &min_x, &min_y, &max_x, &max_y);
// 排序
sort_points(temp_pts, base->num_cells);
// 检查是否重复
bool duplicate = false;
for (int i = 0; i < info.num_rotations; i++) {
if (info.rotations[i].num_points == base->num_cells &&
points_equal(info.rotations[i].points, temp_pts, base->num_cells)) {
duplicate = true;
break;
}
}
if (!duplicate) {
Point *pts = malloc(base->num_cells * sizeof(Point));
memcpy(pts, temp_pts, base->num_cells * sizeof(Point));
Rotation *r = &info.rotations[info.num_rotations];
r->points = pts;
r->num_points = base->num_cells;
r->width = max_x - min_x + 1; // min_x = 0
r->height = max_y - min_y + 1;
info.num_rotations++;
}
}
return info;
}
// 释放 ShapeInfo
void free_shape_info(ShapeInfo *info) {
for (int i = 0; i < info->num_rotations; i++)
free(info->rotations[i].points);
free(info->rotations);
}
// ---------- DLX 操作 ----------
void cover(Node *col) {
col->left->right = col->right;
col->right->left = col->left;
Node *i = col->down;
while (i != col) {
Node *j = i->right;
while (j != i) {
j->down->up = j->up;
j->up->down = j->down;
j->col->size--;
j = j->right;
}
i = i->down;
}
}
void uncover(Node *col) {
Node *i = col->up;
while (i != col) {
Node *j = i->left;
while (j != i) {
j->col->size++;
j->down->up = j;
j->up->down = j;
j = j->left;
}
i = i->up;
}
col->left->right = col;
col->right->left = col;
}
// 搜索函数
bool search(Node *header_node) {
if (header_node->right == header_node)
return true; // 所有列已覆盖
// 选择最小 size 的列
Node *col = header_node->right;
Node *best = col;
int min_size = col->size;
col = col->right;
while (col != header_node) {
if (col->size < min_size) {
min_size = col->size;
best = col;
if (min_size == 0) break;
}
col = col->right;
}
if (min_size == 0) return false;
cover(best);
Node *r = best->down;
while (r != best) {
int shape_idx = row_to_shape[r->rowid];
if (shape_remaining[shape_idx] > 0) {
// 覆盖该行其他列
Node *j = r->right;
while (j != r) {
cover(j->col);
j = j->right;
}
// 更新状态
shape_remaining[shape_idx]--;
solution_rows[depth++] = r->rowid;
if (search(header_node))
return true;
// 回溯
depth--;
shape_remaining[shape_idx]++;
// 解覆盖其他列
j = r->left;
while (j != r) {
uncover(j->col);
j = j->left;
}
}
r = r->down;
}
uncover(best);
return false;
}
// ---------- 主函数 ----------
int main() {
char input[1000];
if (fgets(input, sizeof(input), stdin) == NULL) {
fprintf(stderr, "No input\n");
return 1;
}
// 移除换行符
input[strcspn(input, "\n")] = 0;
// 移除所有空格(简化解析)
char *src = input, *dst = input;
while (*src) {
if (*src != ' ') *dst++ = *src;
src++;
}
*dst = 0;
// 解析宽度和高度
char *p = strchr(input, '[');
if (!p) { fprintf(stderr, "Invalid input format\n"); return 1; }
char head[100];
strncpy(head, input, p - input);
head[p - input] = '\0';
if (sscanf(head, "%d,%d", &W, &H) != 2) {
fprintf(stderr, "Parse error: width and height\n");
return 1;
}
// 解析形状列表
char *q = strrchr(input, ']');
if (!q) { fprintf(stderr, "Missing ']'\n"); return 1; }
char inside[500];
strncpy(inside, p + 1, q - p - 1);
inside[q - p - 1] = '\0';
input_shapes = malloc(10 * sizeof(ShapeItem)); // 假设最多10种形状
input_shape_count = 0;
char *token = strtok(inside, ",");
while (token) {
char letter = token[0];
token = strtok(NULL, ",");
if (!token) { fprintf(stderr, "Missing count for %c\n", letter); return 1; }
int count = atoi(token);
input_shapes[input_shape_count].letter = letter;
input_shapes[input_shape_count].count = count;
input_shape_count++;
token = strtok(NULL, ",");
}
// 为每个输入形状生成旋转信息
shapes_info = malloc(input_shape_count * sizeof(ShapeInfo));
for (int i = 0; i < input_shape_count; i++) {
char letter = input_shapes[i].letter;
ShapeBase *base = find_shape_base(letter);
if (!base) {
fprintf(stderr, "Unsupported shape letter: %c\n", letter);
return 1;
}
shapes_info[i] = generate_shape_info(base);
}
// 计算总放置数 (dry run)
total_rows = 0;
for (int i = 0; i < input_shape_count; i++) {
ShapeInfo *info = &shapes_info[i];
for (int r = 0; r < info->num_rotations; r++) {
Rotation *rot = &info->rotations[r];
int px = W - rot->width + 1;
int py = H - rot->height + 1;
if (px > 0 && py > 0)
total_rows += px * py;
}
}
if (total_rows == 0) {
printf("No solution\n");
return 0;
}
// 分配数组
row_to_shape = malloc(total_rows * sizeof(int));
row_first_nodes = malloc(total_rows * sizeof(Node*));
solution_rows = malloc(total_rows * sizeof(int));
// 构建列头
total_cols = W * H;
col_headers = malloc(total_cols * sizeof(Node));
header = malloc(sizeof(Node));
// 初始化 header
header->right = header;
header->left = header;
header->up = header;
header->down = header;
header->rowid = -1;
header->size = 0;
// 初始化列头并连接
for (int i = 0; i < total_cols; i++) {
Node *c = &col_headers[i];
c->left = c;
c->right = c;
c->up = c;
c->down = c;
c->col = c;
c->rowid = -1;
c->size = 0;
// 插入 header 左侧链表
c->right = header;
c->left = header->left;
header->left->right = c;
header->left = c;
}
// 构建节点(真实构建)
int current_row_id = 0;
for (int idx = 0; idx < input_shape_count; idx++) {
ShapeInfo *info = &shapes_info[idx];
for (int r = 0; r < info->num_rotations; r++) {
Rotation *rot = &info->rotations[r];
int px = W - rot->width + 1;
int py = H - rot->height + 1;
if (px <= 0 || py <= 0) continue;
for (int i = 0; i < px; i++) {
for (int j = 0; j < py; j++) {
Node *row_start = NULL;
for (int p = 0; p < rot->num_points; p++) {
int x = i + rot->points[p].x;
int y = j + rot->points[p].y;
int col_idx = y * W + x; // 列索引
Node *node = malloc(sizeof(Node));
node->rowid = current_row_id;
node->col = &col_headers[col_idx];
// 插入列链表底部
node->up = node->col->up;
node->down = node->col;
node->col->up->down = node;
node->col->up = node;
node->col->size++;
// 行链表
if (row_start == NULL) {
row_start = node;
node->left = node->right = node;
} else {
node->right = row_start;
node->left = row_start->left;
row_start->left->right = node;
row_start->left = node;
}
}
row_to_shape[current_row_id] = idx;
row_first_nodes[current_row_id] = row_start;
current_row_id++;
}
}
}
}
// 初始化形状剩余数量
shape_remaining = malloc(input_shape_count * sizeof(int));
for (int i = 0; i < input_shape_count; i++)
shape_remaining[i] = input_shapes[i].count;
depth = 0;
// 执行搜索
bool found = search(header);
if (found) {
// 创建网格
char **grid = malloc(H * sizeof(char*));
for (int y = 0; y < H; y++) {
grid[y] = malloc(W + 1);
for (int x = 0; x < W; x++)
grid[y][x] = '?';
grid[y][W] = '\0';
}
// 填充网格
for (int i = 0; i < depth; i++) {
int rowid = solution_rows[i];
int shape_idx = row_to_shape[rowid];
char letter = shapes_info[shape_idx].letter;
Node *node = row_first_nodes[rowid];
Node *start = node;
Node *cur = start;
do {
int col_idx = cur->col - col_headers;
int x = col_idx % W;
int y = col_idx / W;
grid[y][x] = letter;
cur = cur->right;
} while (cur != start);
}
// 输出
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
printf("%c", grid[y][x]);
if (x < W - 1) printf(" ");
}
printf("\n");
free(grid[y]);
}
free(grid);
} else {
printf("No solution\n");
}
// 释放内存(略,程序结束可不释放)
// 清理形状信息
for (int i = 0; i < input_shape_count; i++)
free_shape_info(&shapes_info[i]);
free(shapes_info);
free(input_shapes);
free(shape_remaining);
free(row_to_shape);
free(row_first_nodes);
free(solution_rows);
free(col_headers);
free(header);
return 0;
}
经测试,上述程序一次性编译通过,而且正确求出了一个简单的覆盖,
gcc dlxt.c -o dlxt
echo 4,4,[A,4,B,6]|./dlxt
A A A A
B B B B
B B B B
B B B B
源代码中给出了我提到的形状,以及他推测的形状,看了他的思考过程,发现他其实知道俄罗斯方块有7种标准形状,只是我的需求没有明确要求支持。关闭深度思考,继续提示
只给出俄罗斯方块7种标准形状:I, J, L, O, S, T, Z适用于上述程序的点集数组定义,不做别的
他给出了
// 替换 shape_bases 数组定义
ShapeBase shape_bases[] = {
{'I', (Point[]){{0,0},{1,0},{2,0},{3,0}}, 4},
{'J', (Point[]){{0,0},{0,1},{1,1},{2,1}}, 4},
{'L', (Point[]){{2,0},{0,1},{1,1},{2,1}}, 4},
{'O', (Point[]){{0,0},{1,0},{0,1},{1,1}}, 4},
{'S', (Point[]){{1,0},{2,0},{0,1},{1,1}}, 4},
{'T', (Point[]){{1,0},{0,1},{1,1},{2,1}}, 4},
{'Z', (Point[]){{0,0},{1,0},{1,1},{2,1}}, 4},
{0, NULL, 0}
};
我将上述代码合并到原有代码,就能解出标准俄罗斯方块的覆盖了。
echo 4,4,[O,1,L,2,I,1]|./dlxt
O O L L
O O L L
L L L L
I I I I
首次试用小米mimo,感觉还可以,和DeepSeek的水平相当,要是提示更精确一点,就不用思考那么长时间,同样能输出需要的结果。


被折叠的 条评论
为什么被折叠?



