Advanced Guide Acwing algorithm study notes dp topics: knapsack problem

\ (Acwing \) algorithm Advanced Learning \ (dp \) Topics: knapsack problem

Knapsack problem:

  • Knapsack problem is linear \ (dp \) a very special kind of model.
  • 01 Backpack: goods can only be used once.
  • Full backpack: items can be used unlimited times.
  • Multiple backpack: Each item has a number of limitations.
  • Backpack group: Each group can only choose one of several groups.

Example. 1 acw278: digital combined

Meaning of the questions:

  • Given \ (n \) numbers, to choose the number of digits and make them as \ (m \) , asked how many kinds of programs.

Ideas:

  • 01 knapsack problem.
  • \ (a_i \) as a volume, \ (m \) as a backpack capacity, \ (F (J) \) on behalf and for the \ (J \) the number of programs.

  • Metastasis equation \ (F (J) = F + (JA (I)) \) .

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e2+10;
const int maxm = 1e4+10;
int a[maxn], n, m, f[maxn];
int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    f[0] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = m; j >= a[i]; j--)
            f[j] += f[j-a[i]];
    cout << f[m] << endl;
    return 0;
}

Example 2 acw279: a natural number of split

The meaning of problems

  • To a natural number \ (n-\) , requires the \ (n-\) split into several additive in the form of an integer, may participate in the digital operation repeated.
  • Find a few programs.

Thinking

  • Full backpack, because a number can be used many times.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e3+10;
const ll mod = 2147483648;
ll f[maxn], n;
int main()
{
    cin >> n;
    f[0] = 1;
    for(int i = 1; i <= n-1; i++)
        for(int j = i; j <= n; j++)
            f[j] = (f[j]+f[j-i])%mod;
    f[n] = (f[n]+mod)%mod;
    cout << f[n] << endl;
    return 0;
}

Example 3 acw280: jury

The meaning of problems

  • There \ (n-\) individuals, each individual has two scores \ (P (I), D (I) \) , selected from the group \ (m \) who find that the program \ (| DP | \) minimum, multiple kind of legitimate program, then select \ (d + p \) the largest group.

data range

  • \(n\leq 200,m\leq 20, p,d\leq 20\)

Thinking

  • Elected very few people, but the score difference is low, so you can sort by the difference between the first program, which is \ (- 400 \) to \ (+ 400 \) scores section.
  • Then we can go to a difference of \ (0 \) program to find, if not go to \ (1, -1 \) there is no such plan, ...
  • Therefore, the definition of \ (f (i, j, k) \) represents the former \ (I \) individuals select \ (J \) individuals and difference of \ (K \) a \ (p + d \) maximum .
  • For each person may only pick or ban, so this is a 01 backpack.
  • Transfer equation \ (: f (i, j , k) = max \ {f (i-1, j, k), f (i, j-1, k- (p_i-d_i)) + (p_i + d_i) \} \) .
#include<bits/stdc++.h>

using namespace std;
const int maxn = 200 + 10;
const int maxm = 800 + 10;
const int base = 400;
int n, m;
int f[maxn][25][maxm];
int p[maxn], d[maxn];
int ans[maxn];

int main()
{
    int cnt = 1;
    while(scanf("%d%d", &n, &m))
    {
        if(n==0 && m==0) break;
        
        for(int i = 1; i <= n; i++)
            scanf("%d%d", &p[i], &d[i]);
        
        memset(f, -0x3f, sizeof(f));
        f[0][0][base] = 0;
        
        for(int i = 1; i <= n; i++)
            for(int j = 0; j <= m; j++)
                for(int k = 0; k < maxm; k++)
                {
                    f[i][j][k] = f[i-1][j][k];
                    int tmp = k-(p[i]-d[i]);
                    if(tmp < 0 || tmp >= maxm) continue;
                    if(j < 1) continue;
                    f[i][j][k] = max(f[i][j][k], f[i-1][j-1][tmp]+p[i]+d[i]);
                }
        
        int v = 0;
        while(f[n][m][base-v] < 0 && f[n][m][base+v] < 0) v++;
        if(f[n][m][base-v] > f[n][m][base+v]) v = base - v;
        else v = base + v;
        
        int i = n, j = m, k = v, tot = 0;
        while(j)
        {
            if(f[i][j][k] == f[i-1][j][k])// 可以不选第i个人
                i--;
            else 
            {
                ans[++tot] = i; //选第i个人
                k -= (p[i]-d[i]);
                i--, j--;
            }
        }
        
        int ansp = 0, ansd = 0;
        for(int i = 1; i <= tot; i++)
        {
            ansp += p[ans[i]];
            ansd += d[ans[i]];
        }
        
        printf("Jury #%d\n", cnt++);
        printf("Best jury has value %d for prosecution and value %d for defence:\n", ansp, ansd);
        for (int i = 1; i <= tot; i ++ ) 
            printf(" %d", ans[i]);
        puts(""); puts("");
    }
    return 0;
}

Example 4 acw281: coins

The meaning of problems

  • For \ (n-\) type of coin, the \ (I \) denominations as \ (a_i \) , an amount of \ (C_i \) a, Q from a plurality of coin selected, Q \ (1 \) to \ (m \ ) intervals can form themselves into the number of face value.

data range

  • \(n\leq 100, m\leq10^5,a_i\leq10^5,c_i\leq10^3\)

Thinking

  • Multiple backpack should be no problem.
  • Multiple backpack write directly is not, in fact, dangerous binary Optimized about getting bigger, monotone queue optimization would be able to control \ (10 ^ 7 \) calculation.
  • But here is the thing to note:
    • This problem is only concerned about the "feasibility" does not concern "optimality."
    • That is, we are only concerned if he can scrape up.
  • Set \ (f (i, j) \) represents the previous \ (I \) th items, a nominal value of \ (J \) if it can be put together.
  • For the first \ (i \) type of coin could add up to \ (j \) are only two possible face value.
    • Minato has been good.
    • \ (ja (i) \) Minato Well, then \ (j \) from \ (ja (i) \) transfer over.
  • Set \ (vis (j) \) represents the first \ (i \) when a state, make up \ (j \) how to use a face value of at least \ (i \) coins.
  • So when the transfer is to scrape out as much as possible with the previous state, so that the first \ (i \) type of coins can achieve "at least" such a possibility.
  • That is to say, for the first \ (i \) states that if his \ (J == to true \) , then you can not have the first \ (i \) kinds of coins.
  • If for \ (j \) instead of \ (to true \) , but \ (f (ja (i) ) == true \) and when there are enough coins, you can transfer.
  • Refer to code.
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e2 + 10;
const int maxm = 1e5 + 10;
bool f[maxm];
int n, m;
int a[maxn], c[maxn];
int vis[maxm];
int main()
{
    while(cin >> n >> m)
    {
        if(n == 0 && m == 0) break;
        memset(f, 0, sizeof(f));
        f[0] = true;
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++) scanf("%d", &c[i]);
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j <= m; j++) vis[j] = 0;
            for(int j = a[i]; j <= m; j++)
                if(!f[j] && f[j-a[i]] && vis[j-a[i]] < c[i]) {
                    f[j] = true;
                    vis[j] = vis[j-a[i]]+1;
                }
        } int ans = 0;
        for(int i = 1; i <= m; i++)
            ans += f[i];
        cout << ans << endl;
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/zxytxdy/p/12161006.html