题目描述
windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。
windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。
如果windy只能粉刷 T 次,他最多能正确粉刷多少格子?
一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。
输入描述:
第一行包含三个整数,N M T。
接下来有N行,每行一个长度为M的字符串,'0'表示红色,'1'表示蓝色。
30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。
100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 。
输出描述:
输出包含一个整数,最多能正确粉刷的格子数。

思路
图片说明
如果是每条木板的第一段,那么肯定是由上一条木板的结尾转移过来,这里注意肯定要进行新的一次涂色,所以转移方程为
图片说明
图片说明
表示从上一条木板的最后一段转移过来,是选择什么颜色以及当前位置颜色是否涂对

如果不是每条木板的第一段,那么肯定是由该条木板的前一段转移过来
图片说明
图片说明
表示当前位置要涂0,那么选择上一段涂0的,涂的次数就不变,选择上一段涂1的那么次数肯定是比上次多一次,在加上该位置是否正确
当前位置涂1,那么选择上一段涂1的,涂的次数不变,选择上一段涂0的,次数比上一次多1,加上该位置是否涂正确。

#include<bits/stdc++.h>
using namespace std;
char mp[55][55];
int dp[55][55][2555][2];///前i条j段涂k次 最后一段涂红/蓝的最多正确格子数
int main()
{
    int n,m,t;
    cin>>n>>m>>t;
    for(int i=1; i<=n; i++)
        cin>>mp[i]+1;

    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            for(int k=1; k<=t; k++)
            {
                if(j==1)
                {
                    dp[i][j][k][0]=max(dp[i-1][m][k-1][0],dp[i-1][m][k-1][1])+(mp[i][j]=='0');
                    dp[i][j][k][1]=max(dp[i-1][m][k-1][0],dp[i-1][m][k-1][1])+(mp[i][j]=='1');
                }
                else
                {
                    dp[i][j][k][0]=max(dp[i][j-1][k][0],dp[i][j-1][k-1][1])+(mp[i][j]=='0');
                    dp[i][j][k][1]=max(dp[i][j-1][k][1],dp[i][j-1][k-1][0])+(mp[i][j]=='1');
                }
            }
        }
    }
    cout<<max(dp[n][m][t][0],dp[n][m][t][1]);

    return 0;
}