-4

I have a rectangular chocolate bar that consists of squares either black, white or mixed. The bar being not bigger than 50x50 squares. I'm supposed to divide the bar between two people(one gets all the white squares and one the black ones, mixed ones don't matter), by cracking it either horizontally or vertically. I'm supposed to find a method with the least amount of such cracks.

I'm given this input:

M N (number of rows, number of columns) and then M rows that are N numbers long(0 means white, 1 means black, 2 is mixed) so for example bar described like this:

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

can be divided by cracking it seven times in total.

And this one needs at least 24 cracks:

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

I was thinking about something like cracking the bar in two pieces so that the sum of sums of future cracks needed to divide two newly made chocolate bar pieces is the least possible from all the possible cracks (which is height -1 + width -1 of the current bar piece being cracked)

I managed, also thanks to zenwraight, to write a code that solves this but I encountered another problem, it is really inefficient and if the starting chocolate bar gets bigger than 30x30 it's practically unusable. Anyway the source code (written in 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);
}

I am aiming to solve this input :

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

in under 2 seconds, which is much much faster time than that of my current program. The minimum amount of cracks for this one is 126.

Petr Kroupa
  • 53
  • 3
  • 8
  • I'm sorry but I'm not sure what am I doing wrong? why am I getting so many downvotes? I think the question is clear enough? – Petr Kroupa Dec 30 '17 at 21:33
  • 1
    Before posting your next question you should go through [the tour](https://stackoverflow.com/tour) and then go to the [Help Section](http://stackoverflow.com/help) to read [What types of questions should I avoid asking?](http://stackoverflow.com/help/on-topic). Then, if you are sure your question fits the rules, read [How to Ask a question on StackOverflow](http://stackoverflow.com/help/how-to-ask) to be able to make a useful, well formed and on-topic question. – gp_sflover Dec 30 '17 at 21:45
  • Well I actually spent quite some time thinking about the solution, but I didn't come up with any reasonable at all, so that's why I asked here. By the way I wasn't asking for a complete working program, just a hint on how to aproach this problem – Petr Kroupa Dec 30 '17 at 21:49
  • The 4x4 matrix can imho be done in 6 cracks: 1.: First line. 2.: First piece from 1st line. 3.: From rest block 3x4 first column. 4.: 2nd column, 5.: last column. 6.: From the 3rd column, crack last row (=piece). 6 steps. – user unknown Apr 25 '18 at 01:21
  • Plese stop posting our homeworks: https://cw.felk.cvut.cz/courses/a4b33alg/task.php?task=chocolate – Jan Skála Jun 12 '18 at 17:10

1 Answers1

1

Nice question, I have an approach in mind which makes use of recursion to tackle the above problem.

So as at each level or step you have two options either to split the bar horizontally or vertically.

So let's understand the algorithm with an example.

Example:-

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

Now let's call our function minBreaks(int n, int m, int matleft, int right)

So at first step if we break is horizontally our matleft will be

0
1
1
2

and matright will be

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

Now similarly if we had broken this vertically our matleft will be

0 1 1 1

and matright will be

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

Now you pass along this matleft and matright in next recursion call

And then at each call when size of row = 1 or col = 1, you can check the connected components of same value and return the count of connected components

Like for example for vertically case of maxleft -> 0 1 1 1, you will return 2.

Similarly for all the cases and the end part of the method will return

min between break horizontally and vertically

Hope this helps!

zenwraight
  • 2,002
  • 1
  • 10
  • 14
  • yes it did help, thanks. I was thinking about something similiar actually. But if I'm getting your idea correctly you're only breaking the matrix right after first row(horizontaly) or column(vertically), but the the thing is you can break the matrix anywhere. Also you're checking if the matrix can't be divided only when the size of column or row is 1? but what if I am to divide 2x2 matrix with only 1s or only 0s? – Petr Kroupa Dec 31 '17 at 15:53
  • anyway I updated the question if you care to check it again. :) – Petr Kroupa Dec 31 '17 at 16:04