题目链接:点击打开链接
题目大意:给出n个杆子,每个杆子有一个长度,每次可以刷一行或一列,问最少刷多少次可以将整个墙刷成黄色。
思路:首先我们能够想到,如果横着刷,为了得到最优解,当前刷的位置的下面也必须横着刷,然后对于每种情况都可以通过n次竖着刷得到整个黄色的墙。
所以我们采取分治的策略进行动态规划,也就是对于每个状态划分为两种情况讨论,如果要刷横向的话,最矮要刷到最矮的柱子的高度才可能得到比竖着刷优的解,然后就变成了多个具有相同性质的规模更小的墙,然后我们可以采取同样的策略进行分治,知道墙只有一根柱子的时候,可以直接通过一次竖着刷得到最优解,每次判断决策时采取先横着刷和直接竖着刷两种方案中较小的方案。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
const int maxn=5520;
int n;
long long dp[maxn][maxn];
long long num[maxn];
void solve(int l,int r,int h)
{
int j;
dp[l][r]=r-l+1;
if(l==r)return ;
long long hh=10000000000;
for(int i=l;i<=r;i++)
hh=min(hh,num[i]);
long long ans=hh-h;//ans记录横着涂掉底层的步数
for(int i=l;i<=r;i++)
{
if(num[i]==hh)continue;
for(j=i;j<=r;j++)
{
if(j==r)break;
if(num[j+1]==hh)break;
}
solve(i,j,hh);
ans+=dp[i][j];
i=j+1;
}
dp[l][r]=min(dp[l][r],ans);
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%I64d",&num[i]);
}
solve(1,n,0);
printf("%I64d\n",dp[1][n]);
memset(dp,0,sizeof dp);
}
return 0;
}