您的位置:首页 > Web前端

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

2015-09-16 13:19 561 查看

题目链接:

codeforces 448C

题目大意:

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

题目分析:

首先我们能够想到,如果横着刷,为了得到最优解,当前刷的位置的下面也必须横着刷,然后对于每种情况都可以通过n次竖着刷得到整个***的墙。

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

AC代码:

#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]
 );
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: