Money Sums#11504

Money Sums (Анализ)

Written by @Yusif_M and @Tuncay_Pashayev.

You have coins and you should make different values with using these coins. In the next line you input n intengers - the value of your coins. For this problem we can use knapsack.

We use array for input the value of our coins. Let's call them a_0, a_1, a_2, ..., a_{n-1}. Then create another array called knapsack. The elements will be knapsack_0, knapsack_1, knapsack_2, ..., knapsack_{k-1}. In this case the intenger k is the maximum value that we can make with using our coins.

Let's explain knapsack. The maximum value that we can get is the sum of our coin's values:

= a_0 + a_1 + a_2 + ... + a_{n-1}

Our first element of array is a_0, if we can make value with using a_0, that means we can make another value with using a_1 and new value will be a_0 + a_1. If we can make value with using a_0 and a_1, that means we can make another value with using a_2. The new values will be:

  1. a_0 + a_1 + a_2

  2. a_0 + a_2

  3. a_1 + a_2

It is going like that till we reach the maximum value - k. In the code we write like this:

Implementation

#define MAX 100001 
int knapsack[MAX];

Creating an array called knapsack. The reason of defining MAX - is, the maximum value of a_i can get is and the maximum value n can get is . The product makes , indexing is starting from , so we add more, it makes elements for knapsack array.

int n,k = 0;
cin >> n; 
int a[n];

We create intenger - n and intenger - k, making and creating another array.

for (int i = 0; i < n; i++)
{
    cin >> a[i]; 
    k += a[i]; 
}

Input array elements and finding maximum value with summing the value of our coins.

knapsack[0] = 1;
for (int i = 0; i < n; i++)
{
    for (int j = k; j >= a[i]; j--)
    {
        if (knapsack[j - a[i]] == 1)
            knapsack[j] = 1;
    }
}

First we need to give value to knapsack_0 otherwise all the elements of array - knapsack will be , so the answer will be wrong. Then we are checking if we were able to create a value using a_i, then we can create a new value with adding a_i to j-a_i to this will give us , so knapsack_j will be also.

int res = 0;
for (int i = 1; i <= k; i++)
{
    if (knapsack[i] == 1)
        res++;
}
cout << res << endl; 

New intenger called res and giving value . If we were able to create value increase the value of by one. is number of different values that we were able to create.

for (int i = 1; i < k; i++)
{
    if (knapsack[i] == 1)
        cout << i << ' ';
} 

Then output all the values that we were able to create.

Full Solution

#include <iostream>
using namespace std;

#define MAX 100001
int knapsack[MAX];

int main()
{
    int n,k = 0;
    cin >> n;
    int a[n];
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        k += a[i];
    }
    knapsack[0] = 1;
    for (int i = 0; i < n; i++)
    {
        for (int j = k; j >= a[i]; j--)
        {
            if (knapsack[j - a[i]] == 1)
                knapsack[j] = 1;
        }
    }
    int res = 0;
    for (int i = 1; i <= k; i++)
    {
        if (knapsack[i] == 1)
            res++;
    }
    cout << res << endl;
    for (int i = 1; i <= k; i++)
    {
        if (knapsack[i] == 1)
            cout << i << ' ';
    }
}

Written by medv.

We need to determine which sums can be obtained by choosing some subset of the coins. Each coin can be:

Therefore, this is a variant of the Knapsack problem.

Let the sum of all coins be S = x_1 + x_2 + ... + x_n. Since n \le 100 and x_i \le 1000, we have S \le 100000. This allows us to store information about every possible sum.

Define

dp[s] = \begin{cases} 1, & \text{if the sum } s \text{ can be obtained},\\ 0, & \text{otherwise}. \end{cases}

Initially, we have not used any coins. The sum is always achievable, so dp[0] = 1. All other values are equal to zero. To speed up the solution, we'll store in a bitset.

For each coin with denomination x_i:

dp = dp | (dp << x_i)

Count the number of set bits, excluding .

Then, iterate through all sums from to and print those for which dp[s] = 1.

Algorithm implementation

In the bitset , we'll store the array.

#define MAX 100010
bitset<MAX> mask;

Read the number of coins . Set dp[0] = 1, since the sum can be obtained by using no coins.

scanf("%d", &n);
mask.set(0);

In the variable , we calculate the sum of the denominations of all coins.

s = 0;

Process all coins one by one in a loop.

for (i = 0; i < n; i++)
{

Process the coin with denomination .

  scanf("%d", &w);
  s += w;
  mask |= (mask << w);
}

Return the number of set bits. However, the sum is always achievable, so it must be excluded.

printf("%d\n", mask.count() - 1);

Print all achievable positive sums.

for (i = 1; i <= s; i++)
  if (mask[i]) printf("%d ", i);
printf("\n");