DP
F - Monochromatic Path (atcoder.jp)
题意
在 n * m (1 <= n, m <= 2000)的网格图中,每个格子有0,1两种,有两种操作
- 将第 i 行元素反转,花费 r[i] 代价
- 将第 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;
}
标签:Monochromatic,int,反转,ll,ABC264,bigoplus,Path,include
From: https://www.cnblogs.com/hzy717zsy/p/16666495.html