藍橋杯 算法提高 和諧宿舍2

題目描述

題目描述
        我的某室友學過素描,牆上有n張他的作品。這些作品都是寬度爲1,高度不定的矩形,從左到右排成一排,且底邊在同一水平線上。
        宿舍評比就要來了,爲了及格,我們決定買不多於m塊的矩形木板,把這些作品和諧掉。要求木板也從左到右排成一排,且底邊與作品的底邊在同一水平線上。
        在能夠把所有作品和諧掉的前提下,我們希望這些木板的面積和最小,問最小面積和。
在這裏插入圖片描述 
輸入格式
        第一行兩個數n和m,表示作品數和木板數;
        第二行n個數Hi,表示從左到右第i個作品的高度。
輸出格式
        一行一個數ans,表示答案。
樣例輸入
        5 2
        4 2 3 5 4
樣例輸出:
        22
數據規模和約定
        對於30%的數據:1<=n,m<=10;
        對於100%的數據:1<=n,m<=100,1<=Hi<=10000。


分析
  • 狀態:
    dp(i,j,k)dp(i, j, k) 表示iijj 的閉區間內給k個木板能得到最小面積。

  • 狀態轉移方程:
    dp(i,j,k)=min{max{a[i]....a[p]}+dp(p+1,j,k1)}dp(i, j, k) = min\{max\{a[i]....a[p]\} + dp(p + 1, j, k - 1)\}

  • 初始狀態: (只有木板全部用完才能是最優解)
    j<ij< ik=0k =0 時, dp(i,j,k)=0dp(i, j, k)=0, 因爲沒有剩餘剩餘素描, 木板也用完。
    j<ij<ik0k \neq 0 時, dp(i,j,k)=INFdp(i, j, k)=INF, 因爲沒有剩餘素描, 但是模板沒有用完。
    iji\leqslant jk==0k == 0 時, dp(i,j,k)=INFdp(i, j, k)=INF, 因爲有剩餘素描, 但是沒有木板了。
    iji\leqslant jk(ji+1)k \geqslant (j - i + 1) 時, dp(i,j,k)=INFdp(i, j, k)=INF, 因爲有剩餘素描, 但板子過多。

    INF設置爲100 * 10000 + 5, 即面積絕對不可能取得的值即可, 使用INT_MAX 存在溢出風險。


記憶化搜索:
#include <bits/stdc++.h>
using namespace std;
const int INF = 1000005;
int dp[101][101][10001];
int a[101], n, m;
// [i, j]
int dfs(int i, int j, int k)
{
    // 剪枝
    // 還有剩餘素描, 但沒有板子了
    if(j >= i && k == 0) return dp[i][j][k] = INF;
    
    // 還有剩餘素描, 但是板子過多
    if(j >= i && k > (j - i + 1)) return dp[i][j][k] = INF;
    
    // 素描覆蓋完, 但是還有剩餘的板子
    if(i > j && k != 0) return INF;

    // 素描覆蓋完, 且沒有剩餘板子了
    if(i > j && k == 0) return 0;

    // 在 i, j, 且剩餘k塊兒木板的最優解
    if(dp[i][j][k] != 0) return dp[i][j][k];
    int ans = INF;
    for(int L = i; L <= j; L++)
    {
        int now = INT_MIN;
        for(int t = i; t <= L; ++t)
        {
            now = max(now, a[t]);
        }
        now = now * (L - i + 1);
        ans = min(ans, now + dfs(L + 1, j, k - 1));
    }
    // 記憶化
    return dp[i][j][k] = ans;
}
int main()
{
#ifdef LOCAL
    freopen("ADV-298.in", "r", stdin);
#endif
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for(int i = 1; i <= n; ++i)
        cin >> a[i];
    int ans = dfs(1, n, m);
    cout << ans << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章