• DP:Making the Grade(POJ 3666)


                      

                        聪明的修路方案

      题目大意:就是农夫要修一条路,现在要求这条路要么就是上升的,要么就是下降的,总代价为∑|a[i]-b[i]|,求代价最低的修路方案, (0 ≤ β≤ 1,000,000,000) , (1 ≤ N ≤ 2,000)

      这一题百分百就是DP了,为什么?我们现在就是要让cost最小,但是我们不知道cost应该怎么才能最小。

      我们可以这么想,因为序列总是上升或者下降的,我们可以考虑上升的情况,假设前几个数组成的最大值为β,我们要考虑从0-β的改变值,然后不断推到第n个序列。

      显然,这样的复杂度为0(Nβ^2),当然这样的复杂度显然是出事的。  

      现在我们想着优化这个东西,我们可以这么想,如果我们像之前那样扫描的话,那么其实我们忽略了一个很重要的事实,就是在变到α(α<β),其实对于α+1~β之内不会对α造成影响,于是我们可以用一个最小值的临时变量储存在α之前的最小值,用这个更新dp即可,那样就少了一次扫β的复杂度

      复杂度变为O(Nβ);

      但是如果仅仅是这样的话,绝对是TLE,因为β实在是太大了。

      那么我们就要用到离散化的思想,把β投影到有限区域中,既然β是大小的函数,那么我们把可以这样对应:我们只用把新的序列按从小到大排列,然后只对下标进行查找就可以了,这样我们就把解的空间变到下标中了。

       最后状态转移方程:dp[i-1][j]=ABS(a[i]-b[j])+min(dp[i-1][j]);(用滚动数组就可以了)

      另外这一题还有一个更快的解法,那就是用左式堆去解,这个我晚一点开一个新的随笔写好了

      

     1 #include <iostream>
     2 #include <functional>
     3 #include <algorithm>
     4 #define ABS(a,b) (a-b) > 0 ? (a-b):(b-a)
     5 
     6 using namespace std;
     7 
     8 static int road[2000];
     9 static int new_road[2000];
    10 static long long dp1[2000];
    11 static long long dp2[2000];
    12 
    13 int fcmop1(const void *a, const void *b)
    14 {
    15     return *(int *)a - *(int *)b;
    16 }
    17 int fcmop2(const void *a, const void *b)
    18 {
    19     return *(int *)b - *(int *)a;
    20 }
    21 
    22 long long Search_Increase(const int);
    23 long long Search_Decrease(const int);
    24 
    25 int main(void)
    26 {
    27     int n;
    28     long long ans1, ans2;
    29     while (~scanf("%d", &n))
    30     {
    31         for (int i = 0; i < n; i++)
    32         {
    33             scanf("%d", &road[i]);
    34             new_road[i] = road[i];
    35         }
    36         qsort(new_road, n, sizeof(int), fcmop1);
    37         ans1 = Search_Increase(n);
    38         printf("%lld", ans1);
    39         /*
    40         这题有问题,只用求不下降序列就可以了,如果求不上升序列会出错
    41         qsort(new_road, n, sizeof(int), fcmop2);
    42         ans2 = Search_Decrease(n);
    43         printf("%lld
    ", min(ans1, ans2));
    44         */
    45     }
    46 
    47     return 0;
    48 }
    49 
    50 long long Search_Increase(const int n)
    51 {
    52     memset(dp1, 0, sizeof(dp1));
    53     memset(dp2, 0, sizeof(dp2));
    54 
    55     long long min_tmp, *dp_tmp = NULL, *p1 = dp1, *p2 = dp2, ans;
    56 
    57     for (int i = 0; i < n; i++)
    58     {
    59         min_tmp = p1[0];
    60         for (int j = 0; j < n; j++)
    61         {
    62             min_tmp = min(min_tmp, p1[j]);
    63             p2[j] = (ABS(road[i], new_road[j])) + min_tmp;
    64         }
    65         dp_tmp = p1; p1 = p2; p2 = dp_tmp;
    66     }
    67     ans = p1[0];
    68     for (int i = 1; i < n; i++)
    69         ans = min(ans, p1[i]);
    70     return ans;
    71 }
    72 
    73 long long Search_Decrease(const int n)
    74 {
    75     memset(dp1, 0, sizeof(dp1));
    76     memset(dp2, 0, sizeof(dp2));
    77 
    78     long long min_tmp, *dp_tmp = NULL, *p1 = dp1, *p2 = dp2, ans;
    79 
    80     for (int i = 0; i < n; i++)
    81     {
    82         min_tmp = p1[0];
    83         for (int j = 0; j < n; j++)
    84         {
    85             min_tmp = min(min_tmp, p1[j]);
    86             p2[j] = ABS(road[i], new_road[j]) + min_tmp;
    87         }
    88         dp_tmp = p1; p1 = p2; p2 = dp_tmp;
    89     }
    90     ans = p1[0];
    91     for (int i = 1; i < n; i++)
    92         ans = min(ans, p1[i]);
    93     return ans;
    94 }

      另外这一题有BUG,那就是只用找不下降序列就可以了,两个都找会出错。。。。。

      

        

  • 相关阅读:
    Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析
    Android应用setContentView与LayoutInflater加载解析机制源码分析
    Android图片加载框架Fresco,Glide,Picasso对比分析
    Android加载外部APK资源
    https 真的安全吗,可以抓包吗,如何防止抓包吗
    Android常见的几种内存泄漏
    Android应用结构之LiveData
    Android Jetpack LiveData解析
    android使用socket实现简单的点对点通信
    如何分析解决Android ANR
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/4916026.html
Copyright © 2020-2023  润新知