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,那就是只用找不下降序列就可以了,两个都找会出错。。。。。

  

    

原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/4916026.html