Codeforces Round #663 (Div. 2) 505(思维,状态压缩dp

Codeforces Round #663 (Div. 2) 505(思维,状态压缩dp)

链接
题意:给一个nm的01矩阵,严格保证 n < = m n<=m n<=m一个好的子矩阵定义为边长为偶数的正方形,并且1的个数为奇数,问最少变化多少次可以把所有子矩阵变成好矩阵,不能变成就是-1
思路:首先对于 n > = 4 n>=4 n>=4,这时候,一定是-1,因为对于4,由4个2
2的矩阵构成,这四个如果是好矩阵,那么4*奇数一定是个偶数,所以只用分类讨论123的情况。

#include<bits/stdc++.h>
using namespace std;
int mp[5][1000010], dp[1000010][10];
bool bit(int a, int b) {return (a & (1 << b));}

bool check2(int a, int b)
{
    return ((bit(a, 0) + bit(a, 1) + bit(b, 0) + bit(b, 1)) % 2 == 1);
}

bool check3(int a, int b)
{
    return (((bit(a, 0) + bit(a, 1) + bit(b, 0) + bit(b, 1)) % 2 == 1) && ((bit(a, 1) + bit(a, 2) + bit(b, 1) + bit(b, 2)) % 2 == 1));
}

int get(int x, int y)
{
    int cnt = 0;
    for (int i = 0; i < 4; i++) {cnt += (bit(x, i) ^ bit(y, i));}
    return cnt;
}

int main()
{
    int n, m;
    cin >> n >> m;
    memset(dp, 0x3f, sizeof (dp));
    if (n >= 4) {cout << -1 <<endl; return 0;}
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            scanf("%1d", &mp[i][j]);
        }
    }

    if (n == 1) {cout << 0 << endl; return 0;}
    if (n == 2) {
        for (int i = 0; i < 4; i++) dp[1][i] = get(i, mp[1][1] * 2 + mp[2][1]);
        for (int i = 2; i <= m; i++) {
            for (int now = 0; now < 4; now++) {
                for (int last = 0; last < 4; last++) {
                    if (check2(now, last)) {
                        dp[i][now] = min(dp[i][now], get(now, mp[1][i] * 2 + mp[2][i]) + dp[i - 1][last]);
                    }
                }
            }
        }
    }
    if (n == 3) {
        for (int i = 0; i < 8; i++) dp[1][i] = get(i, mp[1][1] * 4 + mp[2][1] * 2 + mp[3][1]);
        for (int i = 2; i <= m; i++) {
            for (int now = 0; now < 8; now++) {
                for (int last = 0; last < 8; last++) {
                    if (check3(now, last)) {
                        dp[i][now] = min(dp[i][now], get(now, mp[1][i] * 4 + mp[2][i] * 2 + mp[3][i]) + dp[i - 1][last]);
                    }
                }
            }
        }
    }
    int ans = 0x3f3f3f3f;
    for (int i = 0; i < 9; i++) {ans = min(ans, dp[m][i]);}
    cout <<ans ;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值