用最少的休息次数划分黑白巧克力棒的算法

时间:2017-12-30 21:27:46

标签: algorithm recursion dynamic-programming rectangles

我有一个矩形巧克力棒,由黑色,白色或混合的方块组成。酒吧不超过50x50平方。我应该在两个人之间划分吧台(一个得到所有的白色方块,一个黑色的,混合的不重要),通过水平或垂直开裂。我应该找到一种裂缝最少的方法。

我给出了这样的意见:

M N(行数,列数) 然后M行是N个数字长(0表示白色,1表示黑色,2表示混合) 所以例如bar描述如下:

4 4
0 1 1 1
1 0 1 0
1 0 1 0
2 0 0 0

可以通过总共七次破解来划分。

这个至少需要24个裂缝:

5 8
0 1 0 1 0 1 0 2
1 0 2 0 2 0 1 0
0 2 0 2 0 1 0 2
1 0 2 0 2 0 1 0
0 1 0 1 0 1 0 2

我正在考虑将这样的条子分成两块,以便将所有可能的裂缝(高度-1 +宽度)中最不可能分割两块新制作的巧克力块所需的未来裂缝总和的总和当前条形件的-1被破裂了)

由于zenwraight,我设法编写了一个代码来解决这个问题,但我遇到了另一个问题,它真的效率很低,如果起始巧克力棒大于30x30,它实际上无法使用。 无论如何源代码(用C编写):

#include <stdio.h>
#include <stdlib.h>

const int M, N;
int ****pieces;
int r = 0;
int ri = 0;
int inf;

void printmatrix(int **mat, int starti, int startj, int maxi, int maxj) {
    for (int i = starti; i < maxi; i++) {
        for (int j = startj; j < maxj; j++) {
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
}

int minbreaks(int **mat, int starti, int startj, int maxi, int maxj, int depth) {
    if (pieces[starti][startj][maxi][maxj] != 0) {
        r++;
        return pieces[starti][startj][maxi][maxj];
    } else {
        ri++;
        int vbreaks[maxj - 1];
        int hbreaks[maxi - 1];
        for (int i = 0; i < maxj; i++) {
            vbreaks[i] = inf;
        }
        for (int i = 0; i < maxi; i++) {
            hbreaks[i] = inf;
        }
        int currentmin = inf;
        for (int i = starti; i < maxi; i++) {
            for (int j = startj; j < maxj - 1; j++) {//traverse trough whole matrix
                if (mat[i][j] != 2) {
                    for (int k = startj + 1; k < maxj; k++) {//traverse all columns
                        if (vbreaks[k - 1] == inf) {//traverse whole column
                            for (int z = starti; z < maxi; z++) {
                                if (mat[z][k] != 2 && mat[i][j] != mat[z][k]) {
                                    /* printmatrix(mat, starti, startj, maxi, maxj);
                                     printf("brokenv in depth:%d->\n", depth);
                                     printmatrix(mat, starti, startj, maxi, k);
                                     printf("and\n");
                                     printmatrix(mat, starti, k, maxi, maxj);
                                     printf("****\n");*/
                                    vbreaks[k - 1] = minbreaks(mat, starti, startj, maxi, k, depth + 1) + minbreaks(mat, starti, k, maxi, maxj, depth + 1);
                                    if (vbreaks[k - 1] < currentmin) {
                                        currentmin = vbreaks[k - 1];
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        for (int i = starti; i < maxi - 1; i++) {
            for (int j = startj; j < maxj; j++) {
                if (mat[i][j] != 2) {
                    for (int k = starti + 1; k < maxi; k++) {
                        if (hbreaks[k - 1] == inf) {
                            for (int z = startj; z < maxj; z++) {
                                if (mat[k][z] != 2 && mat[i][j] != mat[k][z]) {
                                    /* printmatrix(mat, starti, startj, maxi, maxj);
                                     printf("brokenh in depth:%d->\n", depth);
                                     printmatrix(mat, starti, startj, k, maxj);
                                     printf("and\n");
                                     printmatrix(mat, k, startj, maxi, maxj);
                                     printf("****\n");*/
                                    hbreaks[k - 1] = minbreaks(mat, starti, startj, k, maxj, depth + 1) + minbreaks(mat, k, startj, maxi, maxj, depth + 1);
                                    if (hbreaks[k - 1] < currentmin) {
                                        currentmin = hbreaks[k - 1];
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        if (currentmin == inf) {
            currentmin = 1;
        }
        pieces[starti][startj][maxi][maxj] = currentmin;
        return currentmin;
    }
}

void alloc(int i, int j) {
    pieces[i][j] = malloc(sizeof (int*)*(M + 1));
    for (int y = i; y < M + 1; y++) {
        pieces[i][j][y] = malloc(sizeof (int)*(N + 1));
        for (int x = j; x < N + 1; x++) {
            pieces[i][j][y][x] = 0;
        }
    }
}

int main(void) {
    FILE *file = fopen("pub08.in", "r");
    //FILE *file = stdin;
    fscanf(file, "%d %d", &M, &N);
    int **mat = malloc(sizeof (int*)*M);
    pieces = malloc(sizeof (int***)*M);
    for (int i = 0; i < M; i++) {
        mat[i] = malloc(sizeof (int)*N);
        pieces[i] = malloc(sizeof (int**)*N);
        for (int j = 0; j < N; j++) {
            int x;
            fscanf(file, "%d", &x);
            mat[i][j] = x;
            alloc(i, j);
        }
    }
    inf = M * (M + 1) * N * (N + 1) / 4 + 1;
    int result = minbreaks(mat, 0, 0, M, N, 0);
    printf("%d\n", result);
    printf("ri:%d,r:%d\n", ri, r);
    return (EXIT_SUCCESS);
}

我的目标是解决这个问题:

40 40
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 2 1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 2 1 2 1 2 0 0 1 2 2 0 0 0 0 0 0 0 0 1 1 2 1 2 0 0 0 0 0 0 0 0 0 0
0 0 0 1 2 2 0 1 1 1 1 1 0 0 1 2 2 0 0 0 0 0 1 0 0 2 2 1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 2 2 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1 1 2 2 0 0 0 1 2 2 1 2 1 0 0 0 0 0 1 2 1 2 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 2 2 1 2 0 0 0 0 0 2 1 2 2 0 0 0 0 0 2 1 2 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 2 2 2 1 1 0 0 0 0 0 2 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 0 0
0 2 1 2 1 0 2 2 2 2 1 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 2 0 2 2 1 0 0 0 0 0 0
0 2 2 1 2 0 1 2 2 1 1 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 0 0 0 0 0
0 2 2 1 2 0 0 0 0 2 1 2 1 2 1 1 2 0 2 0 0 0 0 0 0 0 1 2 2 2 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 2 2 2 2 1 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 1 2 1 1 2 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 2 0 0 0 0
0 0 0 0 0 0 0 2 1 2 0 0 2 2 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 1 0 0 0 0
0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 2 0 0 0 0
0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 2 2 1 0 0 0 0 2 0 1 1 1 2 1 2 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 0 0 0 0 0 0 2 1 2 2 2 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 0 0 0 0 0 0 1 2 1 1 2 2 0 0 0 0 0
0 0 0 0 0 0 1 2 1 2 2 1 0 0 0 0 0 0 0 1 2 1 2 0 0 0 0 0 0 0 0 0 2 1 2 0 0 0 0 0
0 0 0 0 0 0 1 2 2 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 2 0 0 0 0 0 0 0 0 0 0 2 1 1 0 0
0 0 0 0 0 0 1 1 1 1 1 2 2 0 0 0 0 0 0 0 0 1 1 1 2 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0
0 0 0 0 0 0 1 2 2 2 1 1 1 0 0 0 0 0 0 0 0 1 2 1 2 0 0 0 0 0 0 0 0 0 0 2 2 2 1 0
0 0 0 0 0 0 0 0 0 1 2 1 2 0 0 0 0 0 0 0 0 1 1 1 2 2 0 0 0 0 0 0 0 0 0 1 2 1 1 0
0 0 0 2 1 1 2 2 0 1 2 1 1 0 0 0 0 0 2 2 1 2 2 1 2 2 0 0 0 0 0 0 0 0 0 1 2 2 2 0
0 0 0 2 2 2 1 1 0 0 1 2 2 2 0 0 0 0 2 2 2 1 1 2 1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 2 1 2 2 1 1 0 2 1 2 1 2 1 2 1 1 2 1 1 1 1 1 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 2 2 2 2 1 0 1 1 1 1 1 1 2 1 1 2 2 1 0 1 2 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 0 0 2 1 1 1 2 1 2 0 0 1 2 1 2 1 2 2 0 0 0 0 0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 2 2 1 1 2 2 1 1 1 1 1 1 1 2 1 0 0 0 0 0 0 0 2 2 2 0 0 0
0 0 0 0 0 0 0 1 1 1 2 0 0 1 1 1 2 2 1 2 2 2 1 0 0 0 1 1 1 0 0 0 0 0 1 2 1 0 0 0
0 0 0 0 0 0 0 2 1 1 2 0 0 0 0 0 0 2 2 2 1 1 1 0 0 0 1 2 2 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 2 2 2 2 0 0 0 0 0 0 2 1 1 1 2 0 0 0 0 1 2 2 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 2 2 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 0 0 0 1 1 2 0 2
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 0 0 0 0 0 0 0 1 2 1 0 0
0 0 0 0 0 0 0 0 0 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 0 0 0 0 0 0 0 1 2 1 0 0
0 0 0 0 0 0 0 0 0 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

在2秒内,这比我当前的节目快得多。这个裂缝的最小裂缝数是126。

1 个答案:

答案 0 :(得分:1)

很好的问题,我有一种方法,它利用递归来解决上述问题。

因此,在每个级别或步骤中,您有两个选项可以水平或垂直分割条。

因此,让我们通过一个例子来理解算法。

示例: -

4 4
0 1 1 1
1 0 1 0
1 0 1 0
2 0 0 0

现在让我们调用我们的函数minBreaks(int n, int m, int matleft, int right)

因此,如果我们横向突破是第一步,我们的matleft将是

0
1
1
2

matright将是

1 1 1
0 1 0
0 1 0
0 0 0

现在类似地,如果我们垂直打破了这个,matleft将是

0 1 1 1

matright将是

1 0 1 0
1 0 1 0
2 0 0 0

现在,您在下一次递归调用中传递此matleftmatright

然后在每次调用时,当行的大小= 1或col = 1时,您可以检查相同值的连接组件并返回连接组件的计数

例如,maxleft的垂直情况 - &gt; 0 1 1 1,您将返回2.

同样适用于所有情况,方法的结尾部分将返回

min between break horizontally and vertically

希望这有帮助!