CF EDU 128 E - Moving Chips
阿新 • • 發佈:2022-05-23
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; }