$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
*/
原文地址:https://www.cnblogs.com/ChenyangXu/p/12723693.html