利用小米mimo为精确覆盖矩形问题C程序添加打乱函数求出更大的解

前文的精确覆盖矩形问题C程序在求解较大的矩形时效率较低,参考早先Javascript程序的经验,让mimo

编写 shuffle数组函数,打乱放置顺序以获得随机解。然后用打乱后的数组构建舞蹈链数据结构,搜索时,收集该列的所有行,打乱行顺序以获得随机解,只编写此函数,以及调用此函数语句,并告知插入的位置,不做别的

第一次给出的程序有错,继续提示

修改后程序执行时内存出错,请检查修改,不做别的,

他查出"而内存出错的原因在于 shuffle_ints 的调用方式:将 Node** 强制转换为 int* 进行洗牌是错误的(在 64 位系统上指针大小不等于 int,会破坏内存)",并且修复了。

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>


// 1. 在 main 开头添加
#include <time.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 形
    {'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},

    {'U', (Point[]){{0,0},{2,0},{0,1},{1,1},{2,1}}, 5}, // 2x3 矩形 (0,0)-(2,1),挖去 (1,0)
    {'V', (Point[]){{1,0},{0,1},{1,1}}, 3},       // 2x2 矩形 (0,0)-(1,1),挖去 (0,0)
    {'X', (Point[]){{1,0},{0,1},{1,1},{2,1},{1,2}}, 5},//T形加上顶部1块

    {0, NULL, 0}
};

// 2. 替换 search 函数为以下代码
// 交换整数
void swap_int(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// Fisher-Yates 洗牌
void shuffle_ints(int *array, int n) {
    for (int i = n - 1; i > 0; i--) {
        int j = rand() % (i + 1);
        swap_int(&array[i], &array[j]);
    }
}


// ---------- 辅助函数 ----------
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;
}
// 3. 修正后的 shuffle 函数:专门为 Node** 数组编写
void shuffle_nodes(Node **array, int n) {
    for (int i = n - 1; i > 0; i--) {
        int j = rand() % (i + 1);
        swap_int((int*)&array[i], (int*)&array[j]); // 安全地交换指针值
    }
}

// 4. 修正后的 search_random 函数
bool search_random(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 **rows_array = malloc(min_size * sizeof(Node*));
    Node *r = best->down;
    int count = 0;
    while (r != best) {
        rows_array[count++] = r;
        r = r->down;
    }

    // 打乱行
    shuffle_nodes(rows_array, min_size);

    // 遍历尝试
    for (int i = 0; i < min_size; i++) {
        r = rows_array[i];
        int shape_idx = row_to_shape[r->rowid];

        if (shape_remaining[shape_idx] > 0) {
            // 1. Cover all columns in this row
            Node *j = r->right;
            while (j != r) {
                cover(j->col);
                j = j->right;
            }

            shape_remaining[shape_idx]--;
            solution_rows[depth++] = r->rowid;

            if (search_random(header_node)) {
                free(rows_array);
                return true;
            }

            // 2. Backtrack: Uncover columns
            depth--;
            shape_remaining[shape_idx]++;

            // 必须从右向左遍历 uncover,且需要再次遍历 r 的列
            // 因为没有 left 指针,我们先收集这些列,或者再次遍历 r
            // 这里再次遍历 r 收集列,然后逆序 uncover
            Node **cols_to_uncover = malloc(min_size * sizeof(Node*));
            int c_count = 0;
            Node *temp = r->right;
            while (temp != r) {
                cols_to_uncover[c_count++] = temp->col;
                temp = temp->right;
            }
            for (int k = c_count - 1; k >= 0; k--) {
                uncover(cols_to_uncover[k]);
            }
            free(cols_to_uncover);
        }
    }

    free(rows_array);
    uncover(best);
    return false;
}

bool search(Node *header_node) {return search_random(header_node);}

// ---------- 主函数 ----------
int main() {
    char input[1000];
    // 在 main 函数内部开头添加
    srand(time(NULL));

    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;
}

以上程序只在搜索过程中随机打乱,而JavaScript版本在建立舞蹈链时就打乱了,继续提示

这版可以解出较大的问题了,还是比较慢。再实现打乱放置顺序,然后用打乱后的数组构建舞蹈链数据结构,不做别的

他没有给出具体代码,而是输出了一堆指令

复制代码
为了实现"先生成并打乱所有放置,再构建舞蹈链",我们需要将原程序中生成放置和插入节点的逻辑拆分。


你需要做以下修改:


1.修改 Node 结构体:添加 left 指针,以便后续方便地遍历整行。
2.编写 insert_row 函数:将一个已存在的行节点插入到对应的列中。
3.重构 build 函数:使用数组暂存生成的行,打乱后逐个插入。

看起来他不记得自己输出的代码了,比如明明Node 结构体中本来就有 left,他却说要添加,只好把原来的代码复制了

你的原代码中build部分代码如下,请改为打乱后bulld逻辑。

这下输出了正确的代码,替换原代码后,一遍过。

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>


// 1. 在 main 开头添加
#include <time.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 形
    {'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},

    {'U', (Point[]){{0,0},{2,0},{0,1},{1,1},{2,1}}, 5}, // 2x3 矩形 (0,0)-(2,1),挖去 (1,0)
    {'V', (Point[]){{1,0},{0,1},{1,1}}, 3},       // 2x2 矩形 (0,0)-(1,1),挖去 (0,0)
    {'X', (Point[]){{1,0},{0,1},{1,1},{2,1},{1,2}}, 5},//T形加上顶部1块

    {0, NULL, 0}
};

// 2. 替换 search 函数为以下代码
// 交换整数
void swap_int(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// Fisher-Yates 洗牌
void shuffle_ints(int *array, int n) {
    for (int i = n - 1; i > 0; i--) {
        int j = rand() % (i + 1);
        swap_int(&array[i], &array[j]);
    }
}


// ---------- 辅助函数 ----------
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;
}
// 3. 修正后的 shuffle 函数:专门为 Node** 数组编写
void shuffle_nodes(Node **array, int n) {
    for (int i = n - 1; i > 0; i--) {
        int j = rand() % (i + 1);
        swap_int((int*)&array[i], (int*)&array[j]); // 安全地交换指针值
    }
}

// 4. 修正后的 search_random 函数
bool search_random(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 **rows_array = malloc(min_size * sizeof(Node*));
    Node *r = best->down;
    int count = 0;
    while (r != best) {
        rows_array[count++] = r;
        r = r->down;
    }

    // 打乱行
    shuffle_nodes(rows_array, min_size);

    // 遍历尝试
    for (int i = 0; i < min_size; i++) {
        r = rows_array[i];
        int shape_idx = row_to_shape[r->rowid];

        if (shape_remaining[shape_idx] > 0) {
            // 1. Cover all columns in this row
            Node *j = r->right;
            while (j != r) {
                cover(j->col);
                j = j->right;
            }

            shape_remaining[shape_idx]--;
            solution_rows[depth++] = r->rowid;

            if (search_random(header_node)) {
                free(rows_array);
                return true;
            }

            // 2. Backtrack: Uncover columns
            depth--;
            shape_remaining[shape_idx]++;

            // 必须从右向左遍历 uncover,且需要再次遍历 r 的列
            // 因为没有 left 指针,我们先收集这些列,或者再次遍历 r
            // 这里再次遍历 r 收集列,然后逆序 uncover
            Node **cols_to_uncover = malloc(min_size * sizeof(Node*));
            int c_count = 0;
            Node *temp = r->right;
            while (temp != r) {
                cols_to_uncover[c_count++] = temp->col;
                temp = temp->right;
            }
            for (int k = c_count - 1; k >= 0; k--) {
                uncover(cols_to_uncover[k]);
            }
            free(cols_to_uncover);
        }
    }

    free(rows_array);
    uncover(best);
    return false;
}

bool search(Node *header_node) {return search_random(header_node);}

// ---------- 主函数 ----------
int main() {
    char input[1000];
    // 在 main 函数内部开头添加
    srand(time(NULL));

    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;
    }

    // --- 新增:用于暂存生成的行节点的数组 ---
    Node **temp_row_buffer = malloc(total_rows * sizeof(Node*));
    int temp_row_count = 0;

    // 1. 生成阶段:创建节点,只连接行内左右,暂不插入列上下关系
    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;
                    Node *prev = 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];

                        // 只做左右连接 (行结构)
                        if (row_start == NULL) {
                            row_start = node;
                            node->left = node;
                            node->right = node;
                            prev = node;
                        } else {
                            node->right = row_start;
                            node->left = prev;
                            prev->right = node;
                            row_start->left = node;
                            prev = node;
                        }
                    }

                    // 存入缓冲区
                    temp_row_buffer[temp_row_count++] = row_start;
                    row_to_shape[current_row_id] = idx;
                    row_first_nodes[current_row_id] = row_start;
                    current_row_id++;
                }
            }
        }
    }

    // 2. 打乱阶段:对缓冲区进行 Fisher-Yates 洗牌
    // 交换函数
    void swap_nodes(Node **a, Node **b) {
        Node *t = *a; *a = *b; *b = t;
    }
    // 洗牌
    for (int i = temp_row_count - 1; i > 0; i--) {
        int j = rand() % (i + 1);
        swap_nodes(&temp_row_buffer[i], &temp_row_buffer[j]);
    }

    // 3. 插入阶段:将打乱后的行插入到列的上下链表中
    for (int k = 0; k < temp_row_count; k++) {
        Node *r = temp_row_buffer[k];
        Node *curr = r;
        do {
            // 插入到对应列的底部
            Node *col = curr->col;
            curr->up = col->up;
            curr->down = col;
            col->up->down = curr;
            col->up = curr;
            col->size++; // 更新列的大小

            curr = curr->right;
        } while (curr != r);
    }

    // 释放临时缓冲区
    free(temp_row_buffer);

    // 初始化形状剩余数量
    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;

    // 执行搜索 (使用原有的 search 函数)
    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;
}

把以上两版分别命名为dlxtrnd.c和dlxtrnd2.c,未打乱的版本dlxt2.c。

现在打乱版本能求解较大的矩形了。而未打乱的版本求不出来。

复制代码
gcc dlxtrnd2.c -o dlxtrnd2 -O3
gcc dlxtrnd.c -o dlxtrnd -O3
gcc dlxt2.c -o dlxt2 -O3
time echo 20,18,[C,12,V,24,L,12,O,12,S,12,T,12,X,12]| ./dlxtrnd
S T T T V V V V V V T C C C C C C C C C
S S T V V V V V V V T T L L L T C C C L
...
C C L S S L O O V S S V X T X X X V V V
L L L L L L O O S S V V T T T X V V V V

real    0m38.189s
user    0m38.178s
sys     0m0.010s
time echo 20,18,[C,12,V,24,L,12,O,12,S,12,T,12,X,12]| ./dlxtrnd2
L O O C S T T T V T T T L L L V V V V T
L O O C S S T V V L T X L L L V C V T T
...
C V L V S S X V O O X S S T S L L O O L
L L L V V S V V O O S S T T T L L O O L

real    0m38.439s
user    0m38.407s
sys     0m0.002s
time echo 20,18,[C,12,V,24,L,12,O,12,S,12,T,12,X,12]| ./dlxt2
^C

real    1m39.898s
user    1m39.903s
sys     0m0.001s
相关推荐
刘发财11 小时前
弃用html2pdf.js,这个html转pdf方案能力是它的几十倍
前端·javascript·github
风象南13 小时前
普通人用AI加持赚到的第一个100块
人工智能·后端
牛奶14 小时前
2026年大模型怎么选?前端人实用对比
前端·人工智能·ai编程
牛奶14 小时前
前端人为什么要学AI?
前端·人工智能·ai编程
地平线开发者16 小时前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮16 小时前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者16 小时前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考17 小时前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
冬奇Lab17 小时前
OpenClaw 源码精读(2):Channel & Routing——一条消息如何找到它的 Agent?
人工智能·开源·源码阅读
冬奇Lab17 小时前
一天一个开源项目(第38篇):Claude Code Telegram - 用 Telegram 远程用 Claude Code,随时随地聊项目
人工智能·开源·资讯