Skip to content

425B

Description

A matrix with n rows and m columns consists of 1s and 0s. (1\leq n,m \leq 100) We are asked to change the matrix with less than k operations. (1\leq k \leq 10) After the change, every connected region is a rectangle. Output the minimal number of operations needed.

Tutorial

The final matrix must look like a chess board but with rectangles of 1s and 0s instead of squares of black and white. So there is a vector x has n values can serve as a pattern of each column. Every column either the same as x or different with x in every value. If we found x, we can easily use greedy to decide how many operations we need to change each column into x or its counter part.

Posit n \leq m. There are two situations. The first is n > k, which means some columns cannot be modified, since m > k (because n \leq m and n > k). If we modify each column, we must use more than k operations which is not allowed. So we just enumerate each column as x and calculate the answer.

The second situation is n \leq k. Since k \leq 10, we can just enumerate all the possible x with O(2^n), and use the same method to calculate the answer.

Solution

#include <cstdio>
#include <algorithm>
using namespace std;

const int MAX_N = 110;
const int MAX_M = 110;

int n, m, opr_num;
int f[MAX_N][MAX_M];
int vec[MAX_N];

void make(int bits)
{
    int i = 0;
    while (bits)
    {
        vec[i++] = bits & 1;
        bits >>= 1;
    }
}

int work()
{
    int ret = 0;
    for (int i = 0; i < m; i++)
    {
        int same = 0;
        int diff = 0;
        for (int j = 0; j < n; j++)
        {
            if (vec[j] == f[j][i])
            {
                same++;
            }else
            {
                diff++;
            }
        }
        ret += min(same, diff);
    }
    return ret;
}

int main()
{
    //input
    scanf("%d%d%d", &n, &m, &opr_num);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (m > n)
            {
                scanf("%d", &f[i][j]);
            }else
            {
                scanf("%d", &f[j][i]);
            }
        }
    }
    if (n > m)
    {
        swap(m, n);
    }

    //work
    int ans = n * m;
    if (n <= opr_num)
    {
        for (int i = 0; i < (1 << n); i++)
        {
            make(i);
            ans = min(ans, work());
        }
    }else
    {
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                vec[j] = f[j][i];
            }
            ans = min(ans, work());
        }
    }
    if (ans > opr_num)
    {
        puts("-1");
    }else
    {
        printf("%d\n", ans);
    }
    return 0;
}