zoukankan      html  css  js  c++  java
  • HihoCoder

    有n堆石子,每次你可以把相邻的最少L堆,最多R堆合并成一堆。

    问把所有石子合并成一堆石子的最少花费是多少。

    如果不能合并,输出0。

    石子合并的变种问题。

    用dp[l][r][k]表示将 l 到 r 之间的石子合并成 k 堆。

    显然是k == 1 时,合并才是需要花费代价的。k >= 2时转移的时候不需要加代价。

    这个我当时非常不理解。然后后来想想确实是这样的。因为k >= 2的状态必然是由 k == 1的时候转移过来的。

    就是说将[l, r]分成k堆,必然要有几堆合并成一堆。

    同理,合并区间长度限制的时候也只在k == 1的时候考虑就好了。

    转移的时候分开按情况转移就好了。

    记忆化搜索的形式老是TLE。我也不知道为啥。。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn = 100 + 10;
    const int INF = 0x3f3f3f3f;
    int n, L, R;
    int dp[maxn][maxn][maxn];
    int sum[maxn], a[maxn];
    
    //int DP(int l, int r, int k)
    //{
    //    if (k > r-l+1) return INF;
    //    if (k == r-l+1) return dp[l][r][k] = 0;
    //    if (dp[l][r][k] != INF) return dp[l][r][k];
    //
    //    if (k == 1)
    //    {
    //        for (int j = L; j <= R; j++)
    //            for (int i = l; i <= r-1; i++)
    //                dp[l][r][k] = min(dp[l][r][k], DP(l, i, j-1)+DP(i+1, r, 1)+sum[r]-sum[l-1]);
    //    }
    //    else
    //    for (int i = l; i <= r-1; i++)
    //        dp[l][r][k] = min(dp[l][r][k], DP(l, i, k-1)+DP(i+1, r, 1));
    //
    //    return dp[l][r][k];
    //}
    
    int main()
    {
        while(~scanf("%d%d%d", &n, &L, &R))
        {
            for (int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i-1]+a[i];
    
            memset(dp, INF, sizeof(dp));
    
            //printf("%d %d
    ", dp[1][1][1], 0x3f3f3f3f);
    
            for (int i = 1; i <= n; i++)
                for (int j = i; j <= n; j++)
                        dp[i][j][j-i+1] = 0;
    
            for (int len = 2; len <= n; len++)
            for (int l = 1; l+len-1 <= n; l++)
            {
                int r = l+len-1;
                for (int j = 2; j <= len; j++)
                    for (int k = l; k <= r-1; k++)
                        dp[l][r][j] = min(dp[l][r][j], dp[l][k][j-1]+dp[k+1][r][1]);
    
                for (int j = L; j <= R; j++)
                    for (int k = l; k <= r-1; k++)
                        dp[l][r][1] = min(dp[l][r][1], dp[l][k][j-1]+dp[k+1][r][1]+sum[r]-sum[l-1]);
            }
    
    
    
    //        int ans = DP(1, n, 1);
            printf("%d
    ", dp[1][n][1]==INF ? 0:dp[1][n][1]);
        }
    }
  • 相关阅读:
    SpringCloud Eureka的一些问题
    git branch---删除命令
    go:cannot find main module;see 'go help modules'
    ERROR: yaml.scanner.ScannerError: while scanning for the next token found character ' ' that cannot
    vscode 打开wsl2:ubuntu中的文件进行编辑保存提示没有权限
    Ubuntu20.04 wechat和qq 字体太小,乱码 #
    ubuntu20.4 微信安装
    centos7中在环境变量中添加了GO的PATH,但依然无效
    直接把linux装在了物理机上
    win10 + linux 双系统安装
  • 原文地址:https://www.cnblogs.com/ruthank/p/9575828.html
Copyright © 2011-2022 走看看