CF EDU 128 E - Moving Chips
E - Moving Chips
线性dp
一开始想贪心,但 wa 在1101个点。。。
正解是 dp
首先根据一点贪心的思想,若最后在第 \(i\) 列,那第 \(i\) 列左边的向右走,第 \(i\) 列右边的向左走肯定是最优的
\(pre[i][j]\) : 最终在 \((i, j)\) ,第 \(j\) 列左边的走到这个位置的步数
\(suf[i][j]\) :最终在 \((i, j)\) ,第 \(j\) 列右边的走到这个位置的步数
注意均不包括第 \(j\) 列的代价
转移:
注意转移是从左右两边第一个 * 开始转移,没有 * 的地方是没有代价的
若从上一列的不同行过来,一定需要两步
若从上一列的相同行过来,如果 \((i,j-1)\) 这一列的另一个元素没有 \(*\) , 则需要一步;若有 \(*\), 则需要把这个星移到 \((i,j-1)\) 需要多一步
\(pre[i][j]=min(pre[1-i][j-1]+2,pre[i][j-1]+1+(s[1-i][j-1]==*))\)
\(suf[i][j]=min(suf[1-i][j+1]+2,suf[i][j+1]+1+(s[1-i][j+1]==*))\)
答案为 \(min(pre[i][j]+suf[i][j]+(s[1-i][j]==*))\)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
void solve()
{
int n;
cin >> n;
string s[2];
cin >> s[0] >> s[1];
int ans = 1e9;
int l, r;
for (int i = 0; i < n; i++)
{
if (s[0][i] == '*' || s[1][i] == '*')
{
l = i;
break;
}
}
for (int i = n - 1; i >= 0; i--)
{
if (s[0][i] == '*' || s[1][i] == '*')
{
r = i;
break;
}
}
int pre[2][n], suf[2][n];
for (int i = 0; i <= 1; i++)
for (int j = 0; j < n; j++)
pre[i][j] = suf[i][j] = 0;
for (int j = l + 1; j <= r; j++)
for (int i = 0; i <= 1; i++)
pre[i][j] = min(pre[1 - i][j - 1] + 2, pre[i][j - 1] + 1 + (s[1 - i][j - 1] == '*'));
for (int j = r - 1; j >= l; j--)
for (int i = 0; i <= 1; i++)
suf[i][j] = min(suf[1 - i][j + 1] + 2, suf[i][j + 1] + 1 + (s[1 - i][j + 1] == '*'));
for (int i = 0; i <= 1; i++)
{
for (int j = l; j <= r; j++)
{
ans = min({
ans,
pre[i][j] + suf[i][j] + (s[1 - i][j] == '*')
});
}
}
cout << ans << endl;
}
int main()
{
int T;
cin >> T;
while (T--)
solve();
return 0;
}