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;
}

posted @ 2022-05-23 11:15  hzy0227  阅读(40)  评论(0编辑  收藏  举报