ACM模版

描述

题解

这道题搞得我挺焦虑的,矩阵不大,可以暴力枚举。

枚举所有的组合,然后在这些组合内部,先固定选取的行,然后遍历列,保证遍历完后,选取的行都是回文的;然后再固定选取的列,接着遍历行,保证遍历完后,选取的列都是回文的;每种组合得到一个需要改动的次数,从所有结果中选取最优的即可。

代码

#include <cstdio>
#include <cstring>

#define PINF 0x3f3f3f3f
#define NINF -PINF
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define FOR(i, f, e) for (int i = f; i < e; i++)

using namespace std;

typedef long long ll;

const int MAXN = 9;

int matrix[MAXN][MAXN];
int tmp[MAXN][MAXN];

void next(int &x)
{
    if (x == 0)
    {
        x = PINF;
    }
    else
    {
        int t1 = x & -x;
        int t2 = x + t1;
        x = t2 | ((x ^ t2) / t1 >> 2);
    }
    return ;
}

int main()
{
    int N, M = 0, Row, Colum, ans = PINF;
    char c[MAXN];
    scanf("%d%d%d", &Row, &Colum, &N);

    // 将矩阵存储到int型数组中
    FOR(i, 0, N)
    {
        scanf("%s", c);
        if (!M)
        {
            M = (int)strlen(c);
        }
        FOR(j, 0, M)
        {
            matrix[i][j] = (c[j] == '1');
        }
    }

    // 初始状态11111111(Row=8)
    int chooseRow = ~(-1 << Row);
    do
    {
        // 初始状态11111111(Colum=8)
        int chooseColum = ~(-1 << Colum);
        do
        {
            memcpy(tmp, matrix, sizeof(matrix));
            int res = 0;
            int getRow[MAXN], getColum[MAXN], posRow = 0, posColum = 0;
            FOR(i, 0, N)
            {
                if (chooseRow & 1 << i)
                {
                    getRow[posRow++] = i;       // 选取的行
                }
            }
            FOR(i, 0, M)
            {
                if (chooseColum & 1 << i)
                {
                    getColum[posColum++] = i;   // 选取的列
                }
            }
            // 固定行查找列(结束后保证行是回文的)
            FOR(i, 0, Row)
            {
                FOR(j, 0, M / 2)
                {
                    int instead = M - 1 - j;
                    // 第j列和第instead列都被选取
                    if ((chooseColum & 1 << j) && (chooseColum & 1 << instead))
                    {
                        int sum = tmp[getRow[i]][j] + tmp[getRow[i]][instead] + tmp[N - 1 - getRow[i]][j] + tmp[N - 1 - getRow[i]][instead];
                        // 四个交叉或对称点的情况,如果小于等于2说明有sum个可以改成0,否则说明有4-sum个可以改成1
                        if (sum <= 2)
                        {
                            res += sum;
                            tmp[getRow[i]][j] = tmp[getRow[i]][instead] = tmp[N - 1 - getRow[i]][j] = tmp[N - 1 - getRow[i]][instead] = 0;
                        }
                        else
                        {
                            res += 4 - sum;
                            tmp[getRow[i]][j] = tmp[getRow[i]][instead] = tmp[N - 1 - getRow[i]][j] = tmp[N - 1 - getRow[i]][instead] = 1;
                        }
                    }
                    // 第j列被选取
                    else if (chooseColum & 1 << j)
                    {
                        int sum = tmp[getRow[i]][j] + tmp[getRow[i]][instead] + tmp[N - 1 - getRow[i]][j];
                        // 三个交叉或对称点的情况,如果小于等于1说明有sum个可以改成0,否则说明有3-sum个可以改成1
                        if (sum <= 1)
                        {
                            res += sum;
                            tmp[getRow[i]][j] = tmp[getRow[i]][instead] = tmp[N - 1 - getRow[i]][j] = 0;
                        }
                        else
                        {
                            res += 3 - sum;
                            tmp[getRow[i]][j] = tmp[getRow[i]][instead] = tmp[N - 1 - getRow[i]][j] = 1;
                        }
                    }
                    // 第instead列被选取
                    else if (chooseColum & 1 << instead)
                    {
                        int sum = tmp[getRow[i]][j] + tmp[getRow[i]][instead] + tmp[N - 1 - getRow[i]][instead];
                        // 三个交叉点或对称的情况,如果小于等于1说明有sum个可以改成0,否则说明有3-sum个可以改成1
                        if (sum <= 1)
                        {
                            res += sum;
                            tmp[getRow[i]][j] = tmp[getRow[i]][instead] = tmp[N - 1 - getRow[i]][instead] = 0;
                        }
                        else
                        {
                            res += 3 - sum;
                            tmp[getRow[i]][j] = tmp[getRow[i]][instead] = tmp[N - 1 - getRow[i]][instead] = 1;
                        }
                    }
                    // 都没有被选取
                    else
                    {
                        int sum = tmp[getRow[i]][j] + tmp[getRow[i]][instead];
                        // 两个对称点的情况,如果等于1说明有1个可以被改成0
                        if (sum == 1)
                        {
                            res++;
                            tmp[getRow[i]][j] = tmp[getRow[i]][instead] = 0;
                        }
                    }
                }
            }
            // 固定列查找行(结束后保证列是回文的)
            FOR(i, 0, Colum)
            {
                FOR(j, 0, N / 2)
                {
                    if (tmp[j][getColum[i]] != tmp[N - 1 - j][getColum[i]])
                    {
                        tmp[j][getColum[i]] = tmp[N - 1 - j][getColum[i]] = 0;
                        res++;
                    }
                }
            }
            if (res < ans)
            {
                ans = res;
            }
            next(chooseColum);  // 下一个状态
        } while (chooseColum < 1 << M);
        next(chooseRow);        // 下一个状态
    } while (chooseRow < 1 << N);

    printf("%d", ans);

    return 0;
}