P3392 涂条纹(DP做法)

题目描述

只要一个由 N×M 个小方块组成的旗帜符合如下规则,就是合法的图案。

  • 从最上方若干行(至少一行)的格子全部是白色的;
  • 接下来若干行(至少一行)的格子全部是蓝色的;
  • 剩下的行(至少一行)全部是红色的;

现有一个棋盘状的布,分成了 N 行 M 列的格子,每个格子是白色蓝色红色之一,小 a 希望把这个布改成合法图案,方法是在一些格子上涂颜料,盖住之前的颜色。

小 A 很懒,希望涂最少的格子,使这块布成为一个合法的图案。

输入格式

第一行是两个整数 N,M。

接下来 N 行是一个矩阵,矩阵的每一个小方块是 W(白),B(蓝),R(红)中的一个。

输出格式

一个整数,表示至少需要涂多少块。

输入输出样例

输入 #1复制

4 5
WRWRW
BWRWB
WRWRW
RWBWR

输出 #1复制

11

说明/提示

样例解释

目标状态是:

WWWWW
BBBBB
RRRRR
RRRRR

一共需要改 11 个格子。

数据范围

对于 100% 的数据,N,M≤50。

做这道题我先用数字记下每一个字符的出现次数,算出来每一行如果全改成这个字符的次数,然后用动态规划,从数组cost[0][0]走到cost[n-1][m-1]的最短路径,接下来就是动态规划的做法了,状态转移:  dp[i][j] = min(dp[i - 1][j],dp[i-1][j-1]) + cost[i][j];

代码如下

#include 
#include 
#include  // for std::min
char a[55][55];
using namespace std;

int minCostPath(vector>& cost, int n) {
    // 初始化 dp 数组
    vector> dp(n, vector(3, 0));

    // 起点
    dp[0][0] = cost[0][0];

    // 初始化第一行
    for (int j = 1; j < 3; ++j) {
        dp[0][j] = dp[0][j - 1] + cost[0][j];
    }

    // 初始化第一列
    for (int i = 1; i < n; ++i) {
        dp[i][0] = dp[i - 1][0] + cost[i][0];
    }

    // 填充 dp 数组
    for (int i = 1; i < n; ++i) {
        for (int j = 1; j < 3; ++j) {
            dp[i][j] = min(dp[i - 1][j],dp[i-1][j-1]) + cost[i][j];
        }
    }

    // 返回结果
    return dp[n-1][2];
}
int main() {
    int n,m;
    cin >> n>>m;

    // 输入费用数组
    vector> cost(n, vector(3));
    for(int i=0;i> a[i][j];
            if(a[i][j]=='W')
                cost[i][0]--;
            if(a[i][j]=='B')
                cost[i][1]--;
            if(a[i][j]=='R')
                cost[i][2]--;
        }
    }

    // 计算最小费用
    int result = minCostPath(cost, n);
    cout << result << endl;

    return 0;
}

你可能感兴趣的:(动态规划,算法)