/*
Problem: Minimum Flip Cost to Create a Same-Color Grid Path
Company Tag: Infosys
Problem Statement:
We are given an N x M binary grid.
We can flip:
- any row i with cost R[i]
- any column j with cost C[j]
Flipping changes 0 to 1 and 1 to 0.
We need a path from top-left to bottom-right such that:
- we only move right or down
- all cells on the path have the same color
Return the minimum total flip cost.
Constraints:
2 <= N <= 1000
2 <= M <= 1000
1 <= R[i] <= 100
1 <= C[j] <= 100
grid[i][j] is either '0' or '1'
A valid solution is always possible.
Simple Brute Force:
Try every possible set of flipped rows and columns.
Why Brute Force Fails:
There are 2^N row choices and 2^M column choices.
Better Idea:
Use dynamic programming on the path.
Final color of cell (i, j) is:
grid[i][j] XOR rowFlip[i] XOR colFlip[j]
We try both target colors:
target = 0
target = 1
DP state:
dp[i][j][rowFlip][colFlip]
Meaning:
minimum cost to reach cell (i, j)
when current row has rowFlip state
and current column has colFlip state.
Dry Run:
Grid:
0 1
1 1
Row costs:
3, 4
Column costs:
5, 2
Flip column 2.
Grid becomes:
0 0
1 0
Path:
(1,1) -> (1,2) -> (2,2)
Total cost = 2
Time Complexity:
O(N * M)
Space Complexity:
O(N * M)
*/
#include <bits/stdc++.h>
using namespace std;
long long minimumFlipCost(
int N,
int M,
vector<int>& rowCost,
vector<int>& colCost,
vector<string>& grid
) {
const long long INF = (1LL << 60);
long long answer = INF;
for (int targetColor = 0; targetColor <= 1; targetColor++) {
/*
Each cell has 4 states:
state 0 -> rowFlip = 0, colFlip = 0
state 1 -> rowFlip = 0, colFlip = 1
state 2 -> rowFlip = 1, colFlip = 0
state 3 -> rowFlip = 1, colFlip = 1
*/
vector<vector<array<long long, 4>>> dp(
N,
vector<array<long long, 4>>(M)
);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
for (int state = 0; state < 4; state++) {
dp[i][j][state] = INF;
}
}
}
for (int rowFlip = 0; rowFlip <= 1; rowFlip++) {
for (int colFlip = 0; colFlip <= 1; colFlip++) {
int finalColor = (grid[0][0] - '0') ^ rowFlip ^ colFlip;
if (finalColor == targetColor) {
long long cost = 0;
if (rowFlip) {
cost += rowCost[0];
}
if (colFlip) {
cost += colCost[0];
}
int state = rowFlip * 2 + colFlip;
dp[0][0][state] = cost;
}
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
for (int state = 0; state < 4; state++) {
long long currentCost = dp[i][j][state];
if (currentCost >= INF) {
continue;
}
int rowFlip = state / 2;
int colFlip = state % 2;
// Move right. Row flip stays the same, new column flip can be chosen.
if (j + 1 < M) {
for (int nextColFlip = 0; nextColFlip <= 1; nextColFlip++) {
int finalColor =
(grid[i][j + 1] - '0') ^ rowFlip ^ nextColFlip;
if (finalColor == targetColor) {
long long newCost = currentCost;
if (nextColFlip) {
newCost += colCost[j + 1];
}
int nextState = rowFlip * 2 + nextColFlip;
dp[i][j + 1][nextState] =
min(dp[i][j + 1][nextState], newCost);
}
}
}
// Move down. Column flip stays the same, new row flip can be chosen.
if (i + 1 < N) {
for (int nextRowFlip = 0; nextRowFlip <= 1; nextRowFlip++) {
int finalColor =
(grid[i + 1][j] - '0') ^ nextRowFlip ^ colFlip;
if (finalColor == targetColor) {
long long newCost = currentCost;
if (nextRowFlip) {
newCost += rowCost[i + 1];
}
int nextState = nextRowFlip * 2 + colFlip;
dp[i + 1][j][nextState] =
min(dp[i + 1][j][nextState], newCost);
}
}
}
}
}
}
for (int state = 0; state < 4; state++) {
answer = min(answer, dp[N - 1][M - 1][state]);
}
}
return answer;
}
int main() {
int N, M;
cin >> N >> M;
vector<int> rowCost(N);
vector<int> colCost(M);
for (int i = 0; i < N; i++) {
cin >> rowCost[i];
}
for (int j = 0; j < M; j++) {
cin >> colCost[j];
}
vector<string> grid(N);
for (int i = 0; i < N; i++) {
cin >> grid[i];
}
cout << minimumFlipCost(N, M, rowCost, colCost, grid) << endl;
return 0;
}