• POJ3666 Making the Grade[动态规划]


    MakingtheGradeMaking-the-Grade


    Description

    链接
    给出数列AA, 求非严格单调递减或递增, 且 S=i=1NAiBiS = sum_{i=1}^{N}∣A_i-B_i∣ 最小的序列 BB


    Solution

    BB非严格单调递增为例, 考虑已经选了NN个数, 最小值怎么取

    N=1N=1, A1=B1A_1=B_1SS 最小;
    N>1N>1时, 假如前面已经选择了N1N-1个数取得了最小值, 考虑怎么取第NN个数
    -  当Ai>=Bi1A_i>=B_{i-1}时, Bi=AiB_i=A_i时显然最优.
    -  当Ai<Bi1A_i<B_{i-1}时,
         -  使Bi=AiB_i=A_i;
    .    -  将Bk,Bk+1...,BiB_k, B_{k+1}..., B_i全部赋值为Ak,Ak+1...,AiA_k, A_{k+1}...,A_i的中位数(根据货仓选址问题显然选择中位数最佳 )

    若按照上方直接模拟, 复杂度不可估量(其实是懒得算, 反正过不了)
    但是可以得出结论 : BB数列中的每个数必定都为AA数列中的元素

    于是可以考虑 dpdp
    dpdp到第ii位为阶段, 为了转移, 状态可设dp[i,j]dp[i, j]表示BB的最后一个元素为AjA_j时的SminS_{min},
    转移方程: dp[i,j]=max{dp[i1,k]+AiAj}dp[i,j] = max{dp[i-1, k]+∣A_i-A_j∣}Ak<=AjA_k<=A_j
    时间复杂度 O(N3)O(N^3)
    AA拷贝到CC数组, sortsort排序后保持决策集合增长时新决策的单调性
    即可实现O(N2)O(N^2)
    具体可以看下方代码


    Code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define reg register
    
    const int maxn = 2005;
    
    int N;
    int A[maxn];
    int C[maxn];
    int dp[maxn][maxn];
    
    int main(){
            scanf("%d", &N);
            for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]), C[i] = A[i];
            std::sort(C+1, C+N+1);
            memset(dp, 0x3f, sizeof dp);
            for(reg int i = 1; i <= N; i ++) dp[0][i] = 0;
            for(reg int i = 1; i <= N; i ++){
                    int minn = 0x3f3f3f3f;
                    for(reg int j = 1; j <= N; j ++){
                            minn = std::min(minn, dp[i-1][j]);
                            dp[i][j] = std::min(dp[i][j], minn + abs(A[i] - C[j]));
                    }
            }
            int Ans = 0x3f3f3f3f;
            for(reg int i = 1; i <= N; i ++) Ans = std::min(Ans, dp[N][i]);
            std::reverse(C+1, C+N+1);
            memset(dp, 0x3f, sizeof dp);
            dp[0][0] = 0;
            for(reg int i = 1; i <= N; i ++){
                    int minn = 0x3f3f3f3f;
                    for(reg int j = 1; j <= N; j ++){
                            minn = std::min(minn, dp[i-1][j]);
                            dp[i][j] = std::min(dp[i][j], minn + abs(A[i] - C[j]));
                    }
            }
            for(reg int i = 1; i <= N; i ++) Ans = std::min(Ans, dp[N][i]);
            printf("%d
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    js实现截图并下载到本地
    div里面的文本内容居中显示
    div里面的p标签内容上下垂直居中
    《将博客搬至CSDN》
    RobotFramework 用例出错后继续操作
    selenium+log4j+eclipse相关问题及解决方案
    linux 安装maven
    LINUX下查看系统参数的常见命令
    Linux常用命令使用
    grep 命令
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822615.html
Copyright © 2020-2023  润新知