$ ACM $レッスン4宿題-動的プログラミング

\(ACM \)クラス4番目の割り当て動的プログラミング


\(A. \パール\)

タイトル

\(n \)の真珠が与えられた場合、各真珠には属性\(a_ {i}、\ p_ {i} \)があり、それぞれ需要の量と価格を表し、真珠は品質の低い順に並べられます。

高品質の真珠を低品質の真珠に置き換える

購入ごとに、現在の品質の真珠の\(10 \)の価格を追加する必要があります

購入する必要がある真珠の最小量を見つける

入力フォーマット

複数のデータセット、\(n \ leq 100、\ a_ {i}、\ p_ {i} \ leq 1000 \)

出力フォーマット

出力最小量

解決策

観察により、低品質の真珠の代わりに高品質の真珠が使用される場合、それらは連続的でなければならないことが判明しました

\(j \)パールの価格の組み合わせを使用し\(i、\ i + 1、\ ... \、\ j \)パールを購入し、\(k、\ i <k <j \ )真珠、そのような購入方法が最適であると仮定

\(i、\ i + 1、\ ... \、\ k \)パール\(k \)番目のパールの価格で購入できるので、価格が安いため、組み合わせ購入は継続的である必要があります

定義\(dp [i] \)は、最初の\(i \)パールを購入するために費やされる最小金額です

その後

\ [dp [i] = max \ left \ {dp [j-1]、\(sum [i]-sum [j-1] + 10)\ cdot p [i]、\ 1 \ leq j \ leq i \正しい\} \]

\(コード\)

#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], " \n"[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\n", 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 \)のシーケンス最大の連続サブシーケンス)を指定して、先頭と末尾を記録します

入力フォーマット

複数のデータセット、\(n \ leq 10000 \)

出力フォーマット

出力合計の最大値、および対応する頭と尾

複数の回答がある場合、出力は辞書式順序で最小です

合計が負の場合、出力\(0、\ 1、\ n \)

解決策

\(dp [i] \)\(a [i] \)で終わる部分列の合計の最大値として定義します

\ [dp [i] = max \ left \ {dp [i-1] + a [i]、\ a [i] \ right \} \]

最大値\(ans \)を記録した後、アレイをもう一度スキャンして、開始と終了を見つけます。

\(コード\)

#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], " \n"[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\n", 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 \×N \)の行列が与えられると、最大の部分行列の合計を求めます

入力フォーマット

複数のデータセット、\(N \ leq 100 \)

出力フォーマット

出力サブマトリックス合計

解決策

2D接頭辞を維持し、

サブマトリックスの左上隅と右下隅を列挙し、差\(O(1)\)を使用して合計計算ます

\(コード\)

#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], " \n"[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];
                //cout<<i<<' '<<j<<' '<<dp[i][j]<<endl;
            }
        }
        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]);
                        //if(dp[s][t] - dp[i - 1][t] - dp[s][j - 1] + dp[i - 1][j - 1] == 23) cout<<i<<' '<<j<<' '<<s<<' '<<t<<endl;
                    }
                }
            }
        }
        printf("%d\n", 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} \)の 2つの属性があり、それぞれ、複数回使用できる量と容量を表します。

容量が\(W = F-E \)のバックパックを考えて、バックパックを満たすのに必要な最低金額を見つけます。

入力フォーマット

複数のデータセット、\(n \ leq 500、\ E、\ F、\ W \ leq 10000、\ P \ leq 50000 \)

出力フォーマット

完全に充填できる場合は、最小量を出力します

完全に埋められない場合は「不可能」を出力

解決策

完全なバックパック

\(コード\)

#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], " \n"[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.\n", 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
*/

おすすめ

転載: www.cnblogs.com/ChenyangXu/p/12723693.html