题目链接: codeforces-1199F.
题目描述
          
\;\;\;\;\;
给出一个
n
⋅
n
n\cdot n
n⋅n网格,每个格子是黑色或白色。
          
\;\;\;\;\;
现在有一种染色方法,每次可以选择一个矩形区域
w
×
h
w \times h
w×h,将其中的所有格子染成白色,代价为
m
a
x
(
w
,
h
)
max(w,h)
max(w,h).
          
\;\;\;\;\;
问:将所有格子染成白色的最小代价。(格子可被重复染色)
          
\;\;\;\;\;
1
≤
n
≤
50
1\leq n \leq 50
1≤n≤50.
思路
      
\;\;\;
这长得像个dp,但我没想到是这样的dp.
      
\;\;\;
f
[
x
1
]
[
y
1
]
[
x
2
]
[
y
2
]
f[x1][y1][x2][y2]
f[x1][y1][x2][y2] 表示将矩形区域
(
x
1
,
y
1
)
→
(
x
2
,
y
2
)
(x1,y1) \rightarrow (x2,y2)
(x1,y1)→(x2,y2) (左上角,右下角)染成白色的最小代价。每次只要将矩形划分为两部分的和求解即可,
      
\;\;\;
初始化:
f
[
x
1
]
[
y
1
]
[
x
2
]
[
y
2
]
=
m
a
x
(
x
2
−
x
1
+
1
,
  
y
2
−
y
1
+
1
)
f[x1][y1][x2][y2]=max(x2-x1+1, \; y2-y1+1)
f[x1][y1][x2][y2]=max(x2−x1+1,y2−y1+1).
      
\;\;\;
转移方程:
          
\;\;\;\;\;
横向分割:
f
[
x
1
]
[
y
1
]
[
x
2
]
[
y
2
]
=
m
i
n
{
f
[
x
1
]
[
y
1
]
[
i
]
[
y
2
]
+
f
[
i
+
1
]
[
y
1
]
[
x
2
]
[
y
2
]
}
f[x1][y1][x2][y2]=min\left \{ f[x1][y1][i][y2] + f[i+1][y1][x2][y2] \right \}
f[x1][y1][x2][y2]=min{f[x1][y1][i][y2]+f[i+1][y1][x2][y2]}
(
x
1
≤
i
<
x
2
)
(x1 \leq i < x2)
(x1≤i<x2).
          
\;\;\;\;\;
纵向分割:
f
[
x
1
]
[
y
1
]
[
x
2
]
[
y
2
]
=
m
i
n
{
f
[
x
1
]
[
y
1
]
[
x
2
]
[
j
]
+
f
[
x
1
]
[
j
+
1
]
[
x
2
]
[
y
2
]
}
f[x1][y1][x2][y2]=min\left \{ f[x1][y1][x2][j] + f[x1][j+1][x2][y2] \right \}
f[x1][y1][x2][y2]=min{f[x1][y1][x2][j]+f[x1][j+1][x2][y2]}
(
y
1
≤
j
<
y
2
)
(y1 \leq j < y2)
(y1≤j<y2).
      
\;\;\;
时间复杂度:
O
(
n
4
)
O(n^{4})
O(n4)
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 55;
int n;
char s[MAXN][MAXN];
int f[MAXN][MAXN][MAXN][MAXN];
int find(int x1, int y1, int x2, int y2) {
if(f[x1][y1][x2][y2] != -1) return f[x1][y1][x2][y2];
if(x1 == x2 && y1 == y2) {
if(s[x1][y1] == '#') f[x1][y1][x2][y2] = 1;
else f[x1][y1][x2][y2] = 0;
return f[x1][y1][x2][y2];
}
f[x1][y1][x2][y2] = max(x2 - x1 + 1, y2 - y1 + 1);
for(int i = x1; i < x2; i++) { // 横着切
if(f[x1][y1][i][y2] == -1) find(x1, y1, i, y2);
if(f[i+1][y1][x2][y2] == -1) find(i+1, y1, x2, y2);
f[x1][y1][x2][y2] = min(f[x1][y1][x2][y2], f[x1][y1][i][y2] + f[i+1][y1][x2][y2]);
}
for(int j = y1; j < y2; j++) { // 竖着切
if(f[x1][y1][x2][j] == -1) find(x1, y1, x2, j);
if(f[x1][j+1][x2][y2] == -1) find(x1, j+1, x2, y2);
f[x1][y1][x2][y2] = min(f[x1][y1][x2][y2], f[x1][y1][x2][j] + f[x1][j+1][x2][y2]);
}
// cout << x1 << " " << y1 << " " << x2 << " " << y2 << " " << f[x1][y1][x2][y2] << " last"<< endl;
return f[x1][y1][x2][y2];
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%s",s[i]+1);
}
memset(f, -1, sizeof(f));
printf("%d\n", find(1,1,n,n));
return 0;
}