zoukankan      html  css  js  c++  java
  • 洛谷P1854 花店橱窗布置

    此题出自 IOI 1999

    此题的难点在于:

    1.如何满足题目所述的顺序问题;

    2.如何记录转移状态。

    首先考虑朴素算法。着眼于问题1,不难想到枚举第一朵花的位置,然后在这个位置左边枚举第二朵花的位置......依此类推。

    思考这个模型,发现其搜索树的状态存在大量重叠,且此问题满足“最优子结构”,“子问题重叠性”,“无后效性”三个dp的基础条件。

    于是考虑dp。

    根据朴素算法,考虑使用一个数组 f[ i ][ j ] 记录前 i 朵花占前 j 个瓶子的最大值。

    于是,可以构造出核心转移:

    for(int i = 2; i <= F; i++)
            for(int j = i; j <= V - F + i; j++)
                for(int k = 1; k < j; k++)
                    if(f[i - 1][k] + B[i][j] > f[i][j])
                    {
                        f[i][j] = f[i - 1][k] + B[i][j];
                        pre[i][j] = k;
                    }

    容易发现,当 f 的值得到更新,意味着从 k 处得到转移,不难想到问题二的解法:记录状态 f[ i ][ j ]的转移来源即可。

    完整代码:

     1 // luogu-judger-enable-o2
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <iostream>
     6 #include <vector>
     7 using namespace std;
     8 const int MAXF = 1e2 + 20;
     9 
    10 inline int read()
    11 {
    12     static int x;
    13     scanf("%d", &x);
    14     return x;
    15 }
    16 
    17 int f[MAXF][MAXF], pre[MAXF][MAXF];
    18 int B[MAXF][MAXF];
    19 int F, V;
    20 
    21 int main()
    22 {
    23     cin>>F>>V;
    24     for(int i = 1; i <= F; i++)
    25         for(int j = 1; j <= V; j++)
    26             B[i][j] = read();
    27 
    28     memset(f, -0x7f, sizeof(f));
    29     for(int i = 1; i <= (V - F + 1); i++)
    30         f[1][i]=B[1][i], pre[1][i] = i;
    31 
    32     for(int i = 2; i <= F; i++)
    33         for(int j = i; j <= V - F + i; j++)
    34             for(int k = 1; k < j; k++)
    35                 if(f[i - 1][k] + B[i][j] > f[i][j])
    36                 {
    37                     f[i][j] = f[i - 1][k] + B[i][j];
    38                     pre[i][j] = k;
    39                 }
    40 
    41     int ans = -0x7f7f7f7f,y;
    42     for(int i = 1; i <= V; i++)
    43         if(ans < f[F][i])
    44              y = i, ans = f[F][i];
    45 
    46     int x = F;
    47     std::vector<int> v;
    48     for(; x >= 1; y = pre[x][y], x--)
    49         v.push_back(y);
    50 
    51     reverse(v.begin(), v.end());
    52     cout<<ans<<endl;
    53     for(int i = 0; i < (int) v.size(); i++)
    54         cout<<v[i]<<" ";
    55     puts("");
    56     return 0;
    57 }

    (不要吐槽奇怪的read()函数,一开始没发现有负数,写的快读,wa了好几遍。。。)

  • 相关阅读:
    问题 L: Robots
    最强阵容
    [学习][Math]康托展开和逆康托展开
    [学习][STL]next_permutation
    [动态规划][数位dp]F(x)
    [动态规划][数位dp]Bomb
    [动态规划][数位dp]不要62
    [动态规划][树形dp]Bichrome Tree
    [思维]Finite Encyclopedia of Integer Sequences
    [二分答案]gpa
  • 原文地址:https://www.cnblogs.com/wsmrxc/p/8955532.html
Copyright © 2011-2022 走看看