You can find the problem description here,
Sample Input 1
10 4
2 5 3 6
Sample Output 1
5
This is a typical knapsack problem with repetitions which can be easily solved by making a transaction table from top left to bottom right. The row of the table is the total number of coin to be changed(total weight in knapsack problem), and the column is the denomination of coins. to make the code clean, one row and one column are added. when it comes to cell[r][c] , it depends on the straight upper value and current weight minus current coin denomination as a index on the left:
cell[r][c]=cell[r−1][c]+{cell[r][c−coins[r−1]]0if(coins[r−1]<c)else
The whole table below shows the solving procedure:
Total->: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
Coins:-> | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
5 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 2 |
3 | 1 | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 3 | 3 | 4 |
6 | 1 | 0 | 1 | 1 | 1 | 2 | 3 | 2 | 4 | 4 | 5 |
code:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
long getWays(long n, vector < long > c){
if (n == 0) return 0;
vector<vector<long>> ways(c.size() + 1, vector<long>(n + 1, 0)); // ways vector
for (int s = 1; s < c.size() + 1; ++s) {
ways[s][0] = 1;
for (int t = 1; t < n + 1; ++t) {
ways[s][t] = ways[s-1][t];
if (c[s-1] <= t) {
ways[s][t] += ways[s][t-c[s-1]];
}
}
}
return ways[c.size()][n];
}
int main() {
int n;
int m;
cin >> n >> m;
vector<long> c(m);
for(int c_i = 0; c_i < m; c_i++){
cin >> c[c_i];
}
// Print the number of ways of making change for 'n' units using coins having the values given by 'c'
long ways = getWays(n, c);
cout << ways << endl;
return 0;
}