Loading

E - Don't Isolate Elements(DP,状态设计)

E - Don't Isolate Elements

题意

​ 给出一个01矩阵,长为 \(n\) ,宽为 \(m\)。现在你可以进行一个操作:任选一行,将其该行上的0变1, 1变0。请问最少需要多少次操作,可以使得整张图是合法的。

​ 合法的定义:图中不存在数量为1的连通块。

思路

​ 显然,这就是一个对行来动态规划的问题,对于每一行,我们有两种状态,要么对其反转,要么保持原状。那大抵就是这样\(f[i][j][k]\),表示使得当前 \(i\) 行都为合法的最小操作次数,\(j\) 表示的是第 \(i\) 行是否反转, \(k\) 表示的是第 \(i+1\) 是否反转,因为如果要验证第 \(i\) 行,需要其上下两行来判断是否合法,那\(i-1\)就可以由上个状态来表示,\(i+1\) 由当前状态表示,这样恰好可以完成我们的check。

代码

​ 关于代码实现有很多细节,一个是为了处理边界问题,把边界赋值为2,这样可以省去特判边界的情况。关于正反图,可以用一个 \(g[0 / 1][N][N]\) 表示,这样我们也可以用 \(0 / 1\) 来表示某行的状态。如何判断合法呢?对于第 \(i\) 行的每个元素,直接看他上下左右有没有相同的,若有一个元素是上下左右都没有相同的,那当前状态不合法。一开始都不合法,需要初始化。递推的起点是 \(f[0][0][1] = f[0][0][0] = 0\)。这里为什么第 1 行反转了还是0呢,因为我们第 \(i\) 的花费是在状态转移到 \(i + 1\) 的时候加上的,而非一开始就加上。

#include <bits/stdc++.h>

using namespace std;
const int N = 1005;
int n, m;
int g[2][N][N];
int f[N][2][2]; //从1到n的最小花费,第i行的正反和第i+1行的正反

bool check(int l, int r, int u, int d, int mid)
{
    return (l != mid && r != mid && u != mid && d != mid);
}

int main()
{
    cin >> n >> m;
    
    memset(f, 0x3f, sizeof f);

    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++)
            cin >> g[0][i][j], g[1][i][j] = (1 - g[0][i][j]);

    for(int i = 0; i <= m + 1; i ++)
        g[0][0][i] = g[1][0][i] = g[0][n + 1][i] = g[1][n + 1][i] = 2;
    for(int i = 0; i <= n + 1; i ++)
        g[0][i][0] = g[1][i][0] = g[0][i][m + 1] = g[1][i][m + 1] = 2;

    f[0][0][0] = f[0][0][1] = 0;
    for(int i = 1; i <= n; i ++)
    {
        for(int a = 0; a < 2; a ++)
            for(int b = 0; b < 2; b ++)
                for(int c = 0; c < 2; c ++)
                {
                    int flag = 0;
                    for(int j = 1; j <= m; j ++)
                    {   
                        flag |= check(g[b][i][j - 1], g[b][i][j + 1], g[a][i - 1][j], g[c][i + 1][j], g[b][i][j]);
                    }
                    if(!flag)
                        f[i][b][c] = min(f[i][b][c], f[i - 1][a][b] + b);
                }
    }
    int res = min(f[n][1][0], f[n][0][0]);
    cout << (res == 0x3f3f3f3f ? -1 : res) << '\n';
}
posted @ 2023-01-01 12:37  DM11  阅读(98)  评论(0编辑  收藏  举报