• 【算法学习笔记】83.排序辅助 动态规划 SJTU OJ 1282 修路


    此题倒是能用贪心骗点分...

    其实对于每一个位置 , 我们知道最后的改善结果一定是原数列中的数 . 

    (因为要尽量减少消耗, 可以考虑减小至和相邻的相同) 有了这个结论之后, 我们就考虑用dp来做这件事情

    首先 存下所有数据于 data[]

    排序data 得到 data_sort[]

    然后用dp[i][j]来表示 前i个元素 以data_sort[j]为结尾 转换成 递增序列的耗费.

    那么我们可以知道

    dp[i][j] = min({dp[i-1][k]}) + | data[i]-  data_sort[j] |

    所以直译为:

    for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j)
    for (int k = 1; k <= j ; ++k)
        tmp = min(tmp,dp[i-1][k]); 
    dp[i][j] = tmp + abs(arr[j]-data[i]);

    但是可以有大大的优化, 因为第三重循环式为了计算从dp[i][1]到dp[i][j]的最小值, 我们可以利用一个数组来dp计算这个最小值.

    所以用ass[i][j]来表示从dp[i][1]到dp[i][j]的最小值,

    那么对于ass[i][j] 的更新 可有 

    ass[i][j] = min(dp[i][j],(j==1 ? INF : (ass[i][j-1])));

    当j=1时,ass[i][1] = dp[i][1]

    当j>=2时,ass[i][j] = min(dp[i][j],ass[i][j-1]);

    所以要先更新dp[i][j]再更新ass[i][j]

    因为j的顺序是从1到n, data_sort[j]是从小到大的,所以就维护了整体的单调性 从而得到了答案.

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    typedef unsigned long long ull;
    const int MaxN = 2000+10;
    const int INF = 2147483600;
    int n;
    
    int data[MaxN];
    int data_sort[MaxN];
    int data_sort_d[MaxN];
    int dp[MaxN][MaxN]; //dp[i][j] 表示前i个数 修补为以data_sort[j]为结尾的序列时的消耗最小体力值
    int ass[MaxN][MaxN];//用来辅助求最小值的dp过程
    
    bool cmp_int_d(const int& a, const int& b){
        return a>b;
    }
    
    void init(){
        cin>>n;
        for (int i = 1; i <= n; ++i)
        {
            cin>>data[i];
            data_sort[i] = data[i];
        }
         sort(data_sort+1,data_sort+n+1);
         for (int i = 1; i <= n; ++i)
         {
             data_sort_d[i] = data_sort[n+1-i];
         }
         memset(dp,0,sizeof(dp));
        memset(ass,0,sizeof(ass)); 
    }
    
    int build(int* arr){
        
        //cout<<"-----
    ";
        for (int i = 1; i <= n; ++i){
            for (int j = 1; j <= n; ++j){
                // for (int k = 1; k <= j ; ++k)
                //     tmp = min(tmp,dp[i-1][k]); 
                dp[i][j] = ass[i-1][j] + abs(arr[j]-data[i]);
                //cout<<dp[i][j]<<" ";
                ass[i][j] = min(dp[i][j],(j==1 ? INF : (ass[i][j-1])));
                //cout<<"("<<ass[i][j]<<") ";
            }
            //cout<<endl;
        }
        int ans = INF;
        for (int i = 1; i <= n; ++i)
            ans = min(ans,dp[n][i]);
        return ans;
    }
    
    
    int main(int argc, char const *argv[])
    {
        init();
        int a = build(data_sort);
        int d = build(data_sort_d);
        //cout<<a<<" "<<d<<endl;
        cout<<min(a,d)<<endl;
        return 0;
    }
  • 相关阅读:
    C语言中的排序算法--冒泡排序,选择排序,希尔排序
    常见算法:C语言求最小公倍数和最大公约数三种算法
    提高软件测试效率的方法探讨
    面试官询问的刁钻问题——以及如何巧妙地应付它们
    软件测试面试--如何测试网页的登录页面
    如何衡量测试效率,如何提高测试效率!
    利用交叉测试提升软件测试效率
    交叉测试的必要性和遇到的问题
    敏捷测试
    HttpWatch工具简介及使用技巧
  • 原文地址:https://www.cnblogs.com/yuchenlin/p/sjtu_oj_1282.html
Copyright © 2020-2023  润新知