牛客周赛32——小红的矩阵修改

 题目:小红的矩阵修改

状态压缩dp,对于每一个串,我们使用一个三进制数表示,由于只有三种字符,我们使用3进制数表示,这样一共就只有81中状态。

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 5e2 + 10;
const int mod  = 1e9 + 7;
int dp[1010][1010]; //dp[i][j]代表前i列,第i列的状态压缩为j的合法方案数
int n,m;
string a[4];
int p3[5] = {1,3,9,27,81};  //状态压缩,我们把red用四位三进制数表示
map<char,int> mp;
int b[4] = {};  //用来存出状态为j的三进制代码

int check(int x){
    for (int i = 0; i < n; ++i) {
        b[i] = x%3;
        x /= 3;
    }
    for (int i = 1; i < n; ++i) {
        if(b[i] == b[i-1]) return 0;    //该状态存在相邻元素相等的情况
    }
    return 1;
}
//重写check函数
int check(int x,int y){
    for (int i = 0; i < n; ++i) {
        if(x%3 == y%3) return 0;
        x /= 3;
        y /= 3;
    }
    return 1;
}

void solve(){
    cin>>n>>m;
    for (int i = 0; i <= n; ++i) {
        cin>>a[i];
    }
    memset(dp,0x3f,sizeof(dp));
    mp['r'] = 0;
    mp['e'] = 1;
    mp['d'] = 2;
    int i;
    ll ans = 1e9;
    for (i = 0; i < m; ++i) {   //枚举每一列的情况
        if(i == 0){ //如果为第一列,就只需要考虑这一列元素是否会出现相邻元素相等的情况
            for (int j = 0; j < p3[n]; ++j) {       //j转换为三进制就代表每一种情况,j最大为81
                if(check(j)){
                    int cnt = 0;
                    for (int k = 0; k < n; ++k) {
                        if(b[k] != mp[a[k][i]]){
                            cnt++;      //如果该状态的第k行与该数组不相同,就代表需要修改,cnt++
                        }
                    }
                     dp[0][j] = min(dp[0][j],cnt);
                }
            }
        } else{     //其它列的情况
            for (int j = 0; j < p3[n]; ++j) {       //j转换为三进制就代表每一种情况,j最大为81
                if(check(j)){
                    int cnt = 0;
                    for (int k = 0; k < n; ++k) {
                        if(b[k] != mp[a[k][i]]){
                            cnt++;      //如果该状态的第k行与该数组不相同,就代表需要修改,cnt++
                        }
                    }
                    //不经需要判断这一列是否满足,还需要判断与前一列是否满足要求
                    for (int k = 0; k < p3[n]; ++k) {
                        if(check(j,k)){
                            dp[i][j] = min(dp[i][j],dp[i-1][k] + cnt);
                        }
                    }
                }
            }
        }
        if(i == m-1){
            for (int j = 0; j < p3[n]; ++j) {
                ans = min(ans, (ll) dp[i][j]);
            }
        }
    }
    cout<<ans<<endl;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t = 1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0 ;
}

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值