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

本文介绍Codeforces448C题目的解决方案,采用动态规划与分治策略求解最少刷墙次数,实现最优路径选取。

题目链接:

codeforces 448C


题目大意:

给出n个杆子,每个杆子有一个长度,每次可以刷一行或一列,问最少刷多少次可以将整个墙刷成黄色。


题目分析:

  • 首先我们能够想到,如果横着刷,为了得到最优解,当前刷的位置的下面也必须横着刷,然后对于每种情况都可以通过n次竖着刷得到整个黄色的墙。
  • 所以我们采取分治的策略进行动态规划,也就是对于每个状态划分为两种情况讨论,如果要刷横向的话,最矮要刷到最矮的柱子的高度才可能得到比竖着刷优的解,然后就变成了多个具有相同性质的规模更小的墙,然后我们可以采取同样的策略进行分治,知道墙只有一根柱子的时候,可以直接通过一次竖着刷得到最优解,每次判断决策时采取先横着刷和直接竖着刷两种方案中较小的方案。 



#include <iostream>
#include <cstdio>
#include <algorithm>
#define MAX 5007

using namespace std;

typedef long long LL;

int n;
LL a[MAX];
LL dp[MAX][MAX];

void solve ( int l , int r , LL h )
{
    dp[l][r] = r-l+1;
    if ( l == r ) return;
    LL hh  = 1LL<<48;
    for ( int i = l ; i <= r ; i++ )
        hh = min ( hh , a[i] );
    LL ans = hh-h;
    for ( int i = l ; i <= r ; i++ )
    {
        if ( a[i] == hh ) continue;
        int j;
        for ( j = i; j <= r ; j++ )
        {
            if ( j == r ) break;
            if ( a[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" , &a[i] );
        solve ( 1 , n , 0 );
        printf ( "%I64d\n" , dp[1][n] );
    }
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int A[5010];
int n;
int solve(int l,int r,int h)
{
    if (l>r) return 0;
    int loc=-1,mini=1<<30;
    int sum=0;
    for (int i=l;i<=r;i++){
        if (mini>A[i])
        {
            mini=A[i];
            loc=i;
        }
            if (A[i]>h) sum++;
    }
    //if (loc==-1) return 0;
    int tmp=A[loc]-h; //即使当前最小板子已经被刷过了,也要继续递归下去,因为还可能有其他板子没刷到,h代表当前已经刷到的高度。
    if (tmp<0) tmp=0;
    return min(sum,solve(l,loc-1,max(A[loc],h))+solve(loc+1,r,max(A[loc],h))+tmp);
}
int main()
{
   // cout<< (1<<30)<<endl;
    while (scanf("%d",&n)!=EOF)
    {
        for (int i=1;i<=n;i++) scanf("%d",&A[i]);
        int ans=solve(1,n,0);
        printf("%d\n",ans);
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值