【问题标题】:Algorithm to divide black and white chocolate bar with least number of breaks用最少的休息次数划分黑白巧克力棒的算法
【发布时间】:2017-12-30 21:27:45
【问题描述】:

我有一个矩形巧克力棒,由黑色、白色或混合的正方形组成。条不大于 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。

【问题讨论】:

  • 很抱歉,但我不确定我做错了什么?为什么我得到这么多反对票?我觉得这个问题够清楚了吧?
  • 在发布下一个问题之前,您应该先通过the tour,然后再转到Help Section 阅读What types of questions should I avoid asking?。然后,如果您确定您的问题符合规则,请阅读 How to Ask a question on StackOverflow 以便能够提出一个有用、格式正确且主题相关的问题。
  • 嗯,其实我花了很多时间思考解决方案,但我没有想出任何合理的方案,所以我才在这里问。顺便说一句,我并不是要一个完整的工作程序,只是提示如何解决这个问题
  • 4x4 矩阵可以在 6 个裂缝中完成: 1.:第一行。 2.:第一行的第一件。 3.:从休息块 3x4 第一列。 4.:第二列,5.:最后一列。 6.:从第 3 列开始,破解最后一行(=piece)。 6 个步骤。

标签: algorithm recursion dynamic-programming rectangles


【解决方案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

然后在每次调用时,当 row = 1 或 col = 1 时,您可以检查相同值的连通分量并返回连通分量的计数

例如对于maxleft -> 0 1 1 1 的垂直大小写,您将返回 2。

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

min between break horizontally and vertically

希望这会有所帮助!

【讨论】:

  • 是的,它确实有帮助,谢谢。我实际上正在考虑类似的事情。但是,如果我正确理解了您的想法,那么您只会在第一行(水平)或列(垂直)之后立即破坏矩阵,但问题是您可以在任何地方破坏矩阵。此外,您正在检查矩阵是否仅在列或行的大小为 1 时才可以划分?但是如果我用 1 或 0 来划分 2x2 矩阵呢?
  • 无论如何,如果您想再次检查,我更新了问题。 :)
猜你喜欢
  • 2017-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多