zoukankan      html  css  js  c++  java
  • $ACM$ 课第四次作业-动态规划

    (ACM) 课第四次作业-动态规划


    (A. Pearls)

    题意

    给定 (n) 个珍珠,每个珍珠具有属性 (a_{i}, p_{i}),分别代表需求量和价格,珍珠按照品质由低到高升序列出

    允许用高品质的珍珠代替低品质的珍珠

    每次购买需要加上 (10) 个当前品质珍珠的价格

    求买下所有需求的珍珠的最少金额

    输入格式

    多组数据,(nleq 100, a_{i}, p_{i}leq 1000)

    输出格式

    输出最小金额

    题解

    观察发现,如果用高品质的珍珠代替低品质的珍珠,他们必须是连续的

    考虑用第 (j) 个珍珠的价格组合购买 (i, i + 1, ...\, j) 的珍珠,单独购买第 (k, i < k < j) 个珍珠,假设这样的购买方式最优

    完全可以用第 (k) 个珍珠的价格购买 (i, i + 1, ...\, k) 的珍珠,这样价格更少,所以组合购买必须连续

    定义 (dp[i]) 是购买到第 (i) 个珍珠所花费的最少金额

    [dp[i] = maxleft{dp[j - 1], (sum[i] - sum[j - 1] + 10)cdot p[i], 1leq jleq i ight} ]

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int MOD = 1e9 + 7;
    const int N = 5e2 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int t, n, a[107], p[107], sum[107], dp[107];
    int main()
    {
        t = read();
        while(t--) {
            memset(dp, inf, sizeof(dp));
            dp[0] = 0;
            n = read();
            for(int i = 1; i <= n; ++i)
                a[i] = read(), p[i] = read();
            for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i];
            for(int i = 1; i <= n; ++i) {
                for(int j = 1; j <= i; ++j) {
                    dp[i] = min(dp[i], dp[j - 1] + (sum[i] - sum[j - 1] + 10) * p[i]);
                }
            }
            printf("%d
    ", dp[n]);
        }
        return 0;
    }
    /*
    6
    -2 11 -4 13 -5 -2
    10
    -10 1 2 3 4 -5 -23 3 7 -21
    6
    5 -8 -3 -2 5 0
    1
    10
    3
    -1 -5 -2
    3
    -1 0 -2
    0
    */
    
    

    (B.) 最大连续子序列

    题意

    给定长为 (n) 的序列,求最大连续子序列的和,并且记录首尾

    输入格式

    多组数据,(nleq 10000)

    输出格式

    输出和的最大值,以及对应的首尾

    若有多个答案,按照字典序最小的输出

    若和为负数,则输出 (0, 1, n)

    题解

    定义 (dp[i]) 为以 (a[i]) 结尾的子序列和的最大值

    [dp[i] = maxleft{dp[i - 1] + a[i], a[i] ight} ]

    记录最大值 (ans) 后,再扫一遍数组求首尾

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int MOD = 1e9 + 7;
    const int N = 5e2 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int t, n, a[10007], dp[10007];
    int main()
    {
        while(scanf("%d", &n) && n) {
            for(int i = 1; i <= n; ++i) a[i] = read();
            int ans = -inf, head = 0, tail = 0;
            for(int i = 1; i <= n; ++i) {
                dp[i] = max(dp[i - 1] + a[i], a[i]);
                ans = max(ans, dp[i]);
            }
            if(ans < 0) ans = 0, head = 1, tail = n;
            else {
                for(int i = 1; i <= n; ++i) {
                    if(dp[i] == ans) {
                        int temp = ans;
                        head = tail = i;
                        for(int j = i; temp; temp -= a[j], j--)
                            head = j;
                        break;
                    }
                }
            }
            printf("%d %d %d
    ", ans, a[head], a[tail]);
        }
        return 0;
    }
    /*
    6
    -2 11 -4 13 -5 -2
    10
    -10 1 2 3 4 -5 -23 3 7 -21
    6
    5 -8 -3 -2 5 0
    1
    10
    3
    -1 -5 -2
    3
    -1 0 -2
    0
    */
    

    (C. To The Max)

    题意

    给定 (N imes N) 的矩阵,求最大子矩阵和

    输入格式

    多组数据,(Nleq 100)

    输出格式

    输出最大子矩阵和

    题解

    维护二维前缀和

    枚举子矩阵左上角和右下角,用差分 (O(1)) 计算和

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int MOD = 1e9 + 7;
    const int N = 1e7 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int n, a[107][107], dp[107][107];
    int main()
    {
        while(cin >> n) {
            for(int i = 1; i <= n; ++i)
                for(int j = 1; j <= n; ++j)
                    a[i][j] = read();
            for(int i = 1; i <= n; ++i)
                for(int j = 1; j <= n; ++j)
                    dp[i][j] = a[i][j] + dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1];
            int ans = -inf;
            for(int s = 1; s <= n; ++s)
                for(int t = 1; t <= n; ++t)
                    for(int i = 1; i <= s; ++i)
                        for(int j = 1; j <= t; ++j)
                            ans = max(ans, dp[s][t] - dp[i - 1][t] - dp[s][j - 1] + dp[i - 1][j - 1]);
            printf("%d
    ", ans);
        }
        return 0;
    }
    /*
    4
    -1 -1 -1 -1
    -1 -1 -1 -1
    -1 -1 -1 -1
    -1 -1 -1 -1
    */
    

    (D. Piggy Bank)

    题意

    (n) 个物品,每个物品有 (p_{i}, w_{i}) 两个属性,分别代表金额与容量,可以取多次

    给定容量为 (W = F - E) 的背包,求装满背包所需要的金额的最小值

    输入格式

    多组数据,(nleq 500, E, F, Wleq 10000, Pleq 50000)

    输出格式

    若能恰好装满,输出最小金额

    若不能恰好装满,输出“不可能”

    题解

    完全背包

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int MOD = 1e9 + 7;
    const int N = 5e2 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int t, e, f, n, v[N], w[N], dp[10007];
    int main()
    {
        t = read();
        while(t--) {
            memset(dp, inf, sizeof(dp));
            dp[0] = 0;
            e = read(), f = read();
            n = read();
            for(int i = 1; i <= n; ++i) v[i] = read(), w[i] = read();
            for(int i = 1; i <= n; ++i)
                for(int j = w[i]; j <= (f - e); ++j)
                    dp[j] = min(dp[j], dp[j - w[i]] + v[i]);
            //cout<<inf<<endl;
            if(dp[(f - e)] != inf) printf("The minimum amount of money in the piggy-bank is %d.
    ", dp[(f - e)]);
            else puts("This is impossible.");
        }
        return 0;
    }
    /*
    3
    10 110
    2
    1 1
    30 50
    10 110
    2
    1 1
    50 30
    1 6
    2
    10 3
    20 4
    */
    
  • 相关阅读:
    一本通 1297:公共子序列
    【未完】一本通 1277:【例9.21】方格取数
    一本通 1295:装箱问题
    一本通 1268:【例9.12】完全背包问题
    【BZOJ4416】阶乘字符串(SHOI2013)-状压DP
    【BZOJ2658】小蓝的好友(ZJOI2012)-扫描线+Treap
    【BZOJ2159】Crash的文明世界-第二类斯特林数+树形DP
    【HDU4336】Card Collector-Min-Max容斥
    【BZOJ3997】组合数学(TJOI2015)-Dilworth定理+DP
    【LOJ2537】Minimax(PKUWC2018)-树形DP+线段树合并
  • 原文地址:https://www.cnblogs.com/ChenyangXu/p/12723693.html
Copyright © 2011-2022 走看看