ABC264 F - Monochromatic Path

DP

F - Monochromatic Path (atcoder.jp)

题意

在 n * m (1 <= n, m <= 2000)的网格图中,每个格子有0,1两种,有两种操作

  1. 将第 i 行元素反转,花费 r[i] 代价
  2. 将第 j 行元素反转,花费 c[i] 代价

进行若干次上述操作后,使得图中存在一条从 (1, 1) 到 (n, m) 的路径,路径上的颜色相同

求最小代价

思路

看到数据规模可以想到很可能是 \(O(n^2)\) 的 dp

可以设 \(f[i][j][0/1][0/1]\) 表示从 (1, 1) 走到了 (i, j) ,且第 i 行是否被反转,第 j 列是否被反转

以向下走为例

\(f[i][j][x][y]\) 可以转移到 \(f[i+1][j][nx][ny]\),因为要保证颜色相同,所以 \(a[i][j]\bigoplus x\bigoplus y==a[i+1][j]\bigoplus nx \bigoplus ny\)

由于是先把所有操作执行完再走,若在 dp 中看作是走一步操作一步的话,当前操作不能改变上一步的颜色

例如从 (i, j) -> (i + 1, j), 这时只能反转第 i + 1 行而不能反转第 j 列

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;

const int N = 2e3 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll f[N][N][2][2];//f[i][j][0/1][0/1]为走到(i, j),第 i 行与第 j 列是否反转过
int n, m;
ll r[N], c[N];
int a[N][N];

ll solve()
{
	memset(f, 0x3f, sizeof f);
	f[1][1][0][0] = 0;
	f[1][1][0][1] = c[1];
	f[1][1][1][0] = r[1];
	f[1][1][1][1] = r[1] + c[1];

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			for (int x : {0, 1})
				for (int y : {0, 1})
					for (int nx : {0, 1})
						for (int ny : {0, 1})
						{
							if (i + 1 <= n && a[i][j] ^ x ^ y == a[i+1][j] ^ nx ^ ny)
							{
								ll cost = (nx ? r[i+1] : 0) + (ny == y ? 0 : INF);
								f[i+1][j][nx][ny] = min(f[i+1][j][nx][ny], f[i][j][x][y] + cost);
							}

							if (j + 1 <= m && a[i][j] ^ x ^ y == a[i][j+1] ^ nx ^ ny)
							{
								ll cost = (nx == x ? 0 : INF) + (ny ? c[j+1] : 0);
								f[i][j+1][nx][ny] = min(f[i][j+1][nx][ny], f[i][j][x][y] + cost);
							}
						}
		}
	}
	ll ans = INF;
	for (int x : {0, 1})
		for (int y : {0, 1})
			ans = min(ans, f[n][m][x][y]);
	return ans;
}

int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		cin >> r[i];
	for (int i = 1; i <= m; i++)
		cin >> c[i];
	char x;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> x;
			a[i][j] = x - '0';
		}
	}
	cout << solve() << endl;
    return 0;
}
posted @ 2022-09-07 17:03  hzy0227  阅读(75)  评论(0编辑  收藏  举报