题意:游戏共有两种操作
操作1,将其中一列的格子全部消除
操作2,选择一个连续的区间,在这个区间里,(不存在某一列为空(已经被消除)),然后让这个区间的每一列都消除一格。
两种操作花费都为1。
现在给出游戏初始的样子,请你计算通过这个游戏的最小花费。
分析:搜索做,对于一个区间来说,如果横着减去每一格中的数,直到出现某一个格子为0,我们则不能粉刷了,然后再对于这个连续区间内的一些连续小区间进行粉刷,中间由于之前粉刷的原因而被0隔开。因此,我们可以递归处理这些因为0而隔开的小区间。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 5005;
int a[N];
int dfs(int l, int r)
{
if (l > r) return 0;
//只剩下一个子区间
if (l == r)
{
if (a[l] == 0) return 0;
else return 1;//一次性消除,花费1
}
int last = l - 1;
int res = 0;
//横着消除每一格
int mn = a[l];
for (int i = l + 1; i <= r; ++i) mn = min(mn, a[i]);
for (int i = l; i <= r; ++i)
{
a[i] -= mn;
//出现0被隔开,递归处理之后的每个小区间
if (a[i] == 0) res += dfs(last + 1, i - 1), last = i;
}
res += dfs(last + 1, r);
//另一种所有格子采用第一种操作的方案
return min(res + mn, r - l + 1);
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
printf("%d
", dfs(1, n));
return 0;
}