原题链接
- 题意:给出 (n imes m) 的矩阵,全部由26个小写字母构成,然后要求构造一种矩阵,要求和原矩阵差别最小,保证每行只有两种字母,列不做要求。保证每个字母相邻是不相同的。
- 题解:没想到构造题也能用dp来做,就是按行dp,可以发现,就好像是枚举所有可能性,然后取 (max) 的操作,不过就是这是按照上一行的状态推下来的,设 (dp_{i,a,b}) 就是第i行然后选择 (a,b) 交替最小花费,然后是通过上一行可行状态转移过来,即$$dp_{i, a, b} = min (dp_{i-1,c, d} + cost_{i, a, b} ) (c
eq d , c
eq a, a
eq b, b
eq d)$$
(cost_{i, a, b}) 应当预处理,时间复杂度为 (O(26^{4}n + 26^{2}nm))
- 代码:
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
using namespace std;
typedef long long ll;
typedef long double lb;
const ll N = 555;
const lb eps = 1e-8;
char mp[N][N];
int dp[N][27][27];
int Cost[N][27][27];
pair<char, char> pre[N][27][27], Now;
int n, m;
int cost(int i, char a, char b) {
int ret = 0;
for (int j = 1; j <= m; j++) {
if (j & 1) {
if (mp[i][j] != a)ret++;
} else if (mp[i][j] != b)ret++;
}
return ret;
}
void change(int i, char a, char b) {
for (int j = 1; j <= m; j++) {
if (j & 1) {
mp[i][j]= a;
} else mp[i][j] = b;
}
}
void solve() {
cin >> n >> m;
memset(dp, 0x3f, sizeof dp);
for (int i = 'a'; i <= 'z'; i++) {
for (int j = 'a'; j <= 'z'; j++) {
dp[0][i - 'a'][j - 'a'] = 0;
}
}
for (int i = 1; i <= n; i++) cin >> (mp[i] + 1);
for (int i = 1; i <= n; i++) {
for (char a = 'a'; a <= 'z'; a++) {
for (char b = 'a'; b <= 'z'; b++) {
if (a == b)continue;
Cost[i][a-'a'][b-'a'] = cost(i, a, b);
}
}
}
for (int i = 1; i <= n; i++) {
for (char a = 'a'; a <= 'z'; a++) {
for (char b = 'a'; b <= 'z'; b++) {
if (a == b)continue;
for (char c = 'a'; c <= 'z' ; c++) {
for (char d = 'a'; d <= 'z'; d++) {
if (c == d)continue;
if (c == a)continue;
if (d == b)continue;
int cos = Cost[i][a-'a'][b- 'a'];
if (dp[i][a - 'a'][b - 'a'] > dp[i-1][c - 'a'][d - 'a'] + cos) {
dp[i][a - 'a'][b - 'a'] = min(dp[i][a - 'a'][b - 'a'], dp[i-1][c - 'a'][d - 'a'] + cos);
pre[i][a - 'a'][b - 'a'] = make_pair(c, d);
}
}
}
}
}
}
int ans = 0x3f3f3f3f;
for (int i = 'a'; i <= 'z'; i++) {
for (int j = 'a'; j <= 'z'; j++) {
if (i == j)continue;
if (ans > dp[n][i - 'a'][j - 'a']) {
ans = dp[n][i - 'a'][j - 'a'];
Now.first = i, Now.second = j;
}
}
}
int now = n;
change(now, Now.first, Now.second);
while (Now.first != 0 && Now.second != 0) {
Now = pre[now][Now.first - 'a'][Now.second - 'a'];
change(--now, Now.first,Now.second);
}
cout << ans << endl;
for (int i = 1; i <= n; i++) {
cout << (mp[i] + 1) << endl;
}
}
signed main() {
ios::sync_with_stdio(0);
int t = 1;//cin >> t;
while (t--) solve();
return 0;
}