PalindromeMatrix
Topcoder #枚举 #dp
枚举回文的行,考虑 \(dp_{i,j}\) 表示前 \(i\) 列和后 \(i\) 列中有 \(j\) 列为回文的列的最小代价
转移要分讨
// Author: xiaruize
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1000000007;
const int N = 15 + 10;
void chkmi(int &x, int y)
{
if (y < x)
x = y;
}
int n, m;
int col, row;
char s[N][N];
int dp[N][N];
bool isrw(int msk, int x)
{
if ((msk >> (x - 1)) & 1)
return true;
return false;
}
void solve()
{
cin >> n;
rep(i, 1, n) cin >> (s[i] + 1);
m = strlen(s[1] + 1);
cin >> row >> col;
debug(row, col);
int res = INF;
rep(msk, 0, (1 << n) - 1)
{
if (__builtin_popcount(msk) < row)
continue;
mms(dp, 0x3f);
dp[0][0] = 0;
rep(i, 1, m / 2)
{
int cst1 = 0, cst2 = 0, cst3 = 0;
rep(j, 1, n / 2)
{
if (s[j][i] != s[n - j + 1][i])
{
cst1++;
if ((isrw(msk, j) && s[j][i] != s[j][m - i + 1]) || (isrw(msk, n - j + 1) && s[n - j + 1][i] != s[n - j + 1][m - i + 1]))
cst1--;
else if (isrw(msk, j) && isrw(msk, n - j + 1))
cst1++;
}
if (s[j][m - i + 1] != s[n - j + 1][m - i + 1])
{
cst2++;
if ((isrw(msk, j) && s[j][i] != s[j][m - i + 1]) || (isrw(msk, n - j + 1) && s[n - j + 1][i] != s[n - j + 1][m - i + 1]))
cst2--;
else if (isrw(msk, j) && isrw(msk, n - j + 1))
cst2++;
}
if (isrw(msk, j) || isrw(msk, n - j + 1))
{
int tmp = (s[j][i] != s[j][m - i + 1]) + (s[j][i] != s[n - j + 1][i]) + (s[j][i] != s[n - j + 1][m - i + 1]);
if (tmp > 2)
tmp = 4 - tmp;
tmp -= (isrw(msk, j) && s[j][i] != s[j][m - i + 1]) + (isrw(msk, n - j + 1) && s[n - j + 1][i] != s[n - j + 1][m - i + 1]);
// assert(tmp >= 0);
cst3 += tmp;
}
else
{
cst3 += (s[j][i] != s[n - j + 1][i]) + (s[j][m - i + 1] != s[n - j + 1][m - i + 1]);
}
}
// if (msk == 899)
// debug(msk, i, cst1, cst2, cst3);
rep(j, 0, i * 2)
{
chkmi(dp[i][j], dp[i - 1][j]);
chkmi(dp[i][j + 1], dp[i - 1][j] + min(cst1, cst2));
chkmi(dp[i][j + 2], dp[i - 1][j] + cst3);
}
}
int cur = 0;
rep(i, 1, n)
{
if (isrw(msk, i))
{
rep(j, 1, m / 2) if (s[i][j] != s[i][m - j + 1])
cur++;
}
}
int mi = INF;
rep(i, col, m) mi = min(mi, dp[m / 2][i]);
res = min(res, cur + mi);
// debug(res, msk, cur, dp[m / 2][col]);
}
cout << res << endl;
}
#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--)
solve();
#ifndef ONLINE_JUDGE
cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
return 0;
}