codeforces 448C C. Painting Fence(分治+dp)

来源:互联网 发布:淘宝增值服务有哪些 编辑:程序博客网 时间:2024/06/11 01:31

题目链接:点击打开链接

题目大意:给出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;}