Can anyone explain me the dynamic algorithm, that finds number of subsets with sum equal to k.
I searched in Google, but cant find any simple explanation! Sorry for my English!
Here is the code:
int numbers[MAX];
int GetmNumberOfSubsets()
{
int dp[MAX];
dp[0] = 1;
int currentSum = 0;
for (int i = 0; i < numbers.length; i++)
{
currentSum += numbers[i];
for (int j = min(sum, currentSum); j >= numbers[i]; j--)
dp[j] += dp[j - numbers[i]];
}
return dp[sum];
}
Your DP solution should be 2-dimensional, 1 dimension for the sum, and 1 dimension for the number of elements.
The recursive formula defining this solution is:
DP(x,i) = 0 x < 0
DP(0,i) = 1
DP(x,0) = 0 x > 0
DP(x,i) = DP(x-numbers[i],i-1) + DP(x,i-1)
And it should be something like:
int dp[MAX+1][sum+1];
int i, x;
for (i = 0; i < MAX+1; i++) {
dp[i][0] = 1;
}
for (x = 1; x < sum+1; x++) {
dp[0][x] = 0
}
for (i = 1; i < MAX+1; i++) {
for (x = 1; x < sum+1; x++) {
dp[i][x] = dp[i-1][x];
if (x >= numbers[i])
dp[i][x] += dp[i][x-numbers[i]];
}
}
return dp[MAX][sum];
(Hope I didn't have minor issues, didn't test it - but it should give you idea how to implement it once recursive formulas are clear)
You can use the following example to find the number of subsets with sum equal to k:
#include <iostream>
using std::cout;
using std::cin;
int count = 0,K;
void noofsubsets(int arr[], int sum, int N){
if(N==0){
if(sum==K)
count++;
return;
}
noofsubsets(arr, sum, N-1);
noofsubsets(arr, sum+arr[N-1], N-1);
}
here is a solution using recursion ...
considering two cases
i) Including first element of an array.
ii) without first array element.
`
def subSetsSumK(arr, v, k) :
if (k == 0) :
for value in v :
print(value, end=" ")
print()
return
if (len(arr)== 0):
return
si=0
v1 = [] + v
v1.append(arr[si])
subSetsSumK(arr[1:], v1, k - arr[si])
subSetsSumK(arr[1:], v, k)
def subSetsSumK(arr, k):
v = []
subSetsSumK(arr,v, k)
# Driver code
arr = [ 2,1,3,2 ]
k_sum = 4
subSetsSumK(arr,k)
Related
I am getting segmentation error , it gives output when only print ans[k] inside the function then it
gives corrct output but in main when I try to print ans[k] then it gives segmentation
i am new at progamming so i don't know more about it so please help me it's my assigment
question is
I have to create a array of factors of a number upto 4 * 10^6
Core Dump/Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you.”
When a piece of code tries to do read and write operation in a read only location in memory or freed block of memory, it is known as core dump.
It is an error indicating memory corruption.
#include <bits/stdc++.h>
using namespace std;
#define int long long int
vector<int> arr(1000001,0);
vector<int> ans;
bool isPrime(int n)
{
if (n <= 1)
return false;
if (n <= 3)
return true;
if (n % 2 == 0 || n % 3 == 0)
return false;
for (int i = 5; i * i <= n; i = i + 6)
if (n % i == 0 || n % (i + 2) == 0)
return false;
return true;
}
void factorpush()
{
for (int k = 5; k <= 4000001; k += 4)
{
if (isPrime(k))
{
arr[k] = 1;
}
}
arr.clear();
ans.clear();
for (int k = 5; k <= 4000001; k += 4)
{
if (arr[k] == 1)
{
int n = (k / 4);
ans[n] = (2 * n) - 1 + k;
}
else
{
vector<int> v;
for (int i = 1; i*i < k; i++)
{
if (k % i == 0)
{
if (k / i == i && i != k)
v.push_back(i);
else
{
if (i != k)
{
v.push_back(i);
}
if (k / i != k)
{
v.push_back(k/ i);
}
}
}
}
int count = k;
int count2 = 0;
for (auto x : v)
{
if (x != 1 && x!=k)
{
int n = (k/4);
count2 += ((2*n - 1)/x);
count += ((2*n - 1)/x)*x;
}
}
int n1 = (k/4);
int val = (2*n1) - 1 - count2;
count += val;
ans[n1] = count;
//cout<<ans[n1]<<"\n";
}
}
}
int32_t main()
{
factorpush();
int n;
cin>>n;
cout<<ans[n]<<"\n";`
return 0;
}
I didn't read your code well and there may be other errors, but at least the combination of
vector<int> arr(1000001,0);
and
for (int k = 5; k <= 4000001; k += 4)
{
if (isPrime(k))
{
arr[k] = 1;
}
}
is bad because arr[k] will go further than allocated.
You have to allocate enough elements like
vector<int> arr(4000002,0);
Also accessing arr[k] and ans[n] after arr.clear(); and ans.clear(); and without adding any elements is bad because the clear() function erases all elements from the vector. Also checking for arr[k] == 1 after the erasure doesn't make sense. Not understanding your code well, it looks like
arr.clear();
ans.clear();
should be replaced with something like
ans.clear();
ans.resize(1000001);
I have the C++ function to do. It works fine, but there are some cases where it works bad - "greedy problem".
My C++ code:
#include <vector>
#include <algorithm>
std::vector<int> ans;
std::vector<int> get_change(const std::vector<int> &denominations, int amount) {
//pure algo
std::vector<int> money = denominations;
std::vector<int> count;
ans.clear();
count.assign(money.size(), 0);
std::sort(money.begin(), money.end());
int summ = amount;
for (int i = count.size()-1; i >= 0; i--) {
count[i] = summ / money[i];
summ = summ % money[i];
if (summ==0)
break;
}
//ans generation
for (int i = 0; i < money.size(); i++)
for (int j = 0; j < count[i]; j++)
ans.push_back(money[i]);
return ans;
}
Greedy problem sample: get_change({ 1, 6, 9 }, 30) will return { 1, 1, 1, 9, 9, 9 }, but not { 6, 6, 9, 9 }.
The task is to improve this algorithm to get the same answer.
One possible approach is backtracking.
Backtracking is a general algorithm for finding all (or some) solutions to some computational problems, notably constraint satisfaction problems, that incrementally builds candidates to the solutions, and abandons a candidate ("backtracks") as soon as it determines that the candidate cannot possibly be completed to a valid solution. (Wikipedia)
Here, we try to determine the number of coins, for each coin.
The candidates are abandonned, as soon as the total number of coins is higher than the current optimal solution. Moreover, here, in a given situation (at step i), we directly calculate the maximum number of coins for coins[i], such that the total sum is not higher than the amount.
Here is a possible implementation:
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int> get_change(const std::vector<int>& denominations, int amount) {
std::vector<int> coins = denominations;
std::vector<int> n_coins(coins.size(), 0);
std::vector<int> n_coins_opt(coins.size(), 0);
int n = coins.size();
std::sort(coins.begin(), coins.end(), std::greater<int>());
int sum = 0; // current sum
int i = 0; // index of the coin being examined
int n_min_coins = amount / coins[n - 1] + 1;
int n_total_coins = 0;
bool up_down = true;
while (true) { // UP
if (up_down) {
n_coins[i] = (amount - sum) / coins[i]; // max number of coins[i]
sum += n_coins[i] * coins[i];
n_total_coins += n_coins[i];
if (sum == amount) {
if (n_total_coins < n_min_coins) {
n_min_coins = n_total_coins;
n_coins_opt = n_coins;
}
up_down = false;
sum -= n_coins[i] * coins[i];
n_total_coins -= n_coins[i];
n_coins[i] = 0;
i--;
}
else {
if (i == (n - 1) || (n_total_coins >= n_min_coins)) { // premature abandon
sum -= n_coins[i] * coins[i];
n_total_coins -= n_coins[i];
n_coins[i] = 0;
up_down = false;
i--;
}
else {
i++;
}
}
}
else { // DOWN
if (i < 0) break;
if (n_coins[i] == 0) {
if (i == 0) break;
i--;
}
else {
sum -= coins[i];
n_coins[i] --;
n_total_coins--;
i++;
up_down = true;
}
}
}
std::vector<int> ans;
for (int i = 0; i < coins.size(); i++)
for (int j = 0; j < n_coins_opt[i]; j++)
ans.push_back(coins[i]);
return ans;
}
int main() {
std::vector<int> coins = { 1, 6, 9 };
int amount = 30;
auto n_coins = get_change(coins, amount);
for (int i = 0; i < n_coins.size(); i++)
std::cout << n_coins[i] << " ";
std::cout << "\n";
return 1;
}
This is a dynamic programming problem.
import java.util.*;
import java.lang.*;
import java.io.*;
class Solution{
public static void main (String[] args) throws java.lang.Exception{
System.out.println(getChange(new int[]{1,6,9},30));
System.out.println(getChange(new int[]{1},3));
System.out.println(getChange(new int[]{4,20,500},450));
}
private static List<Integer> getChange(int[] denominations,int amount){
Arrays.sort(denominations);
List<Integer> ans = new ArrayList<>();
if(amount <= 0 || denominations[0] > amount) return ans;
int[][] dp = new int[amount + 1][2];
for(int i=0;i<denominations.length;++i){
if(denominations[i] > amount) break;
dp[denominations[i]][0] = 1;
dp[denominations[i]][1] = 0;
for(int j=denominations[i] + 1;j<=amount;++j){
if(dp[j-denominations[i]][0] > 0 && (dp[j][0] == 0 || dp[j-denominations[i]][0] + 1 < dp[j][0])){
dp[j][0] = dp[j-denominations[i]][0] + 1;
dp[j][1] = j-denominations[i];
}
}
}
if(dp[amount][0] > 0){
while(dp[amount][0] != 0){
ans.add(amount - dp[amount][1]);
amount = dp[amount][1];
}
}
return ans;
}
}
Demo: https://ideone.com/2fYg4F
Algorithm:
This is similar to coin change problem.
We first sort the numbers in the array for uniform computation.
Now, we iterate on all array elements and make each array element loop over all possible amounts from that element till final amount.
Now, we can make amount j(which is a sum) only if we have made sum j - denominations[i].
While doing so, we also check for minimum number of coins needed. If amount j with current denominations[i] needs lesser coins than the current value stored in dp[j][0], then we update the answer in dp[j] accordingly.
In the end, we just loop over the exact coins needed and return the answer.
What is dp[][]:
It's just a simple 2D array where the 0th column keeps track of minimum number of coins
needed in it's first index and 2nd index has the previous coin index that give it the
minimal value.
The 2nd index in dp[][] would ease out the calculation to find the exact coin value as we would have to just do amount - dp[amount][1] to get the coin value.
In the end, we just do a check of dp[amount][0] value. If it's value is 0, we don't have a solution, else we compute it.
I am adaptated vivek_23's dynamic solution to required C++ language.
std::vector<int> get_change2(const std::vector<int>& coins, int amount) {
std::vector<int> denominations = coins;
std::sort(denominations.begin(), denominations.end());
std::vector<int> ans;
if (amount <= 0 || denominations[0] > amount)
return ans;
int** dp = new int* [amount + 1];
for (int i = 0; i < amount + 1; i++) {
dp[i] = new int[2];
dp[i][0] = 0;
dp[i][1] = 0;
}
for (int i = 0; i < denominations.size(); i++) {
if (denominations[i] > amount) break;
dp[denominations[i]][0] = 1;
dp[denominations[i]][1] = 0;
for (int j = denominations[i] + 1; j <= amount; ++j) {
if (dp[j - denominations[i]][0] > 0 && (dp[j][0] == 0 || dp[j - denominations[i]][0] + 1 < dp[j][0])) {
dp[j][0] = dp[j - denominations[i]][0] + 1;
dp[j][1] = j - denominations[i];
}
}
}
if (dp[amount][0] > 0) {
while (dp[amount][0] != 0) {
ans.push_back(amount - dp[amount][1]);
amount = dp[amount][1];
}
}
return ans;
}
Given an array "s" of "n" items, you have for each item an left value "L[i]" and right value "R[i]" and its strength "S[i]",if you pick an element you can not pick L[i] elements on immediate left of it and R[i] on immediate right of it, find the maximum strength possible.
Example input:
5 //n
1 3 7 3 7 //strength
0 0 2 2 2 //Left Value
3 0 1 0 0 //Right Value
Output:
10
Code:
#include < bits / stdc++.h >
using namespace std;
unsigned long int getMax(int n, int * s, int * l, int * r) {
unsigned long int dyn[n + 1] = {};
dyn[1] = s[1];
for (int i = 2; i <= n; i++) {
dyn[i] = dyn[i - 1];
unsigned long int onInc = s[i];
int left = i - l[i] - 1;
if (left >= 1) {
unsigned int k = left;
while ((k > 0) && ((r[k] + k) >= i)) {
k--;
}
if (k != 0) {
if ((dyn[k] + s[i]) > dyn[i]) {
onInc = dyn[k] + s[i];
}
}
}
dyn[i] = (dyn[i] > onInc) ? dyn[i] : onInc;
}
return dyn[n];
}
int main() {
int n;
cin >> n;
int s[n + 1] = {}, l[n + 1] = {}, r[n + 1] = {};
for (int i = 1; i <= n; i++) {
cin >> s[i];
}
for (int i = 1; i <= n; i++) {
cin >> l[i];
}
for (int i = 1; i <= n; i++) {
cin >> r[i];
}
cout << getMax(n, s, l, r) << endl;
return 0;
}
Problem in your approach:
In your DP table, the information you are storing is about maximum possible so far. The information regarding whether the ith index has been considered is lost. You can consider taking strength at current index to extend previous indices only if any of the previously seen indices is either not in range or it is in range and has not been considered.
Solution:
Reconfigure your DP recurrence. Let DP[i] denote the maximum answer if ith index was considered. Now you will only need to extend those that satisfy range condition. The answer would be maximum value of all DP indices.
Code:
vector<long> DP(n,0);
DP[0]=strength[0]; // base condition
for(int i = 1; i < n ; i++){
DP[i] = strength[i];
for(int j = 0; j < i ; j++){
if(j >= (i-l[i]) || i <= (j+r[j])){ // can't extend
}
else{
DP[i]=max(DP[i],strength[i]+DP[j]); // extend to maximize result
}
}
}
long ans=*max_element(DP.begin(),DP.end());
Time Complexity: O(n^2)
Possible Optimizations:
There are better ways to calculate maximum values which you might want to look into. You can start by looking into Segment tree and Binary Indexed Trees.
How to apply longest common subsequence on bigger strings (600000 characters). Is there any way to do it in DP? I have done this for shorter strings.
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int dp[1005][1005];
char a[1005], b[1005];
int lcs(int x,int y)
{
if(x==strlen(a)||y==strlen(b))
return 0;
if(dp[x][y]!=-1)
return dp[x][y];
else if(a[x]==b[y])
dp[x][y]=1+lcs(x+1,y+1);
else
dp[x][y]=max(lcs(x+1,y),lcs(x,y+1));
return dp[x][y];
}
int main()
{
while(gets(a)&&gets(b))
{
memset(dp,-1,sizeof(dp));
int ret=lcs(0,0);
printf("%d\n",ret);
}
}
You should take a look at this article which discusses the various design and implementation considerations. It is pointed out that you can look at Hirschberg's algorithm that finds optimal alignments between two strings using Edit distance (or Levenshtein distance). It can simplify the amount of space required on your behalf.
At the bottom you will find the "space-efficient LCS" defined thusly as a kind of mixed/pseudocode where m is the length of A and n is the length of B:
int lcs_length(char *A, char *B) {
// Allocate storage for one-dimensional arrays X and Y.
for (int i = m; i >= 0; i--) {
for (int j = n; j >= 0; j--) {
if (A[i] == '\0' || B[j] == '\0') {
X[j] = 0;
}
else if (A[i] == B[j]) {
X[j] = 1 + Y[j+1];
}
else {
X[j] = max(Y[j], X[j+1]);
}
}
// Copy contents of X into Y. Note that the "=" operator here
// might not do what you expect. If Y and X are pointers then
// it will assign the address and not copy the contents, so in
// that case you'd do a memcpy. But they could be a custom
// data type with an overridden "=" operator.
Y = X;
}
return X[0];
}
If you are interested here is a paper about LCS on strings from large alphabets. Find algorithm Approx2LCS in section 3.2.
First, use bottom-up approach of dynamic programming:
// #includes and using namespace std;
const int SIZE = 1000;
int dp[SIZE + 1][SIZE + 1];
char a[SIZE + 1], b[SIZE + 1];
int lcs_bottomUp(){
int strlenA = strlen(a), strlenB = strlen(b);
for(int y = 0; y <= strlenB; y++)
dp[strlenA][y] = 0;
for(int x = strlenA - 1; x >= 0; x--){
dp[x][strlenB] = 0;
for(int y = strlenB - 1; y >= 0; y--)
dp[x][y] = (a[x]==b[y]) ? 1 + dp[x+1][y+1] :
max(dp[x+1][y], dp[x][y+1]);
}
return dp[0][0];
}
int main(){
while(gets(a) && gets(b)){
printf("%d\n", lcs_bottomUp());
}
}
Observe that you only need to keep 2 rows (or columns), one for dp[x] and another for dp[x + 1]:
// #includes and using namespace std;
const int SIZE = 1000;
int dp_x[SIZE + 1]; // dp[x]
int dp_xp1[SIZE + 1]; // dp[x + 1]
char a[SIZE + 1], b[SIZE + 1];
int lcs_bottomUp_2row(){
int strlenA = strlen(a), strlenB = strlen(b);
for(int y = 0; y <= strlenB; y++)
dp_x[y] = 0; // assume x == strlenA
for(int x = strlenA - 1; x >= 0; x--){
// x has been decreased
memcpy(dp_xp1, dp_x, sizeof(dp_x)); // dp[x + 1] <- dp[x]
dp_x[strlenB] = 0;
for(int y = strlenB - 1; y >= 0 ; y--)
dp_x[y] = (a[x]==b[y]) ? 1 + dp_xp1[y+1] :
max(dp_xp1[y], dp_x[y+1]);
}
return dp_x[0]; // assume x == 0
}
int main(){
while(gets(a) && gets(b)){
printf("%d\n", lcs_bottomUp_2row());
}
}
Now it's safe to change SIZE to 600000.
As OP stated, the other answers are taking too much time, mainly due to the fact that for each outter iteration, 600000 characters are being copied.
To improve it, one could, instead of physically changing column, change it logically. Thus:
int spaceEfficientLCS(std::string a, std::string b){
int i, j, n = a.size(), m = b.size();
// Size of columns is based on the size of the biggest string
int maxLength = (n < m) ? m : n;
int costs1[maxLength+1], costs2[maxLength+1];
// Fill in data for costs columns
for (i = 0; i <= maxLength; i++){
costs1[i] = 0;
costs2[i] = 0;
}
// Choose columns in a way that the return value will be costs1[0]
int* mainCol, *secCol;
if (n%2){
mainCol = costs2;
secCol = costs1;
}
else{
mainCol = costs1;
secCol = costs2;
}
// Compute costs
for (i = n; i >= 0; i--){
for (j = m; j >= 0; j--){
if (a[i] == '\0' || b[j] == '\0') mainCol[j] = 0;
else mainCol[j] = (a[i] == b[j]) ? secCol[j+1] + 1 :
std::max(secCol[j], mainCol[j+1]);
}
// Switch logic column
int* aux = mainCol;
mainCol = secCol;
secCol = aux;
}
return costs1[0];
}
I know how to code the solution for the 0-1 knapsack problem. However, I do not know how to change this code such that we can pick multiple copies of the same item. So, for each item i , we have another paramter k(i) which denotes the number of copies of i present. I will be obliged if someone could help me with this. Below is my code when k(i) = 1. Look at the knapsack function for a top down dp solution
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
int n, g;
int p[1005],w[1005];
int dp[1004][35];// num of object and weight left
int knapsack(int resourcel, int item){
//if(resourcel < 0) return (1<<31);
if(item == n) return 0;
if(resourcel == 0) return 0;
if(dp[item][resourcel] != -1) return dp[item][resourcel];
if(resourcel - w[item] < 0){
dp[item][resourcel] = knapsack(resourcel,item+1);
return dp[item][resourcel];
}
else{
int take = knapsack(resourcel - w[item],item+1) + p[item];
int notTake = knapsack(resourcel,item+1);
dp[item][resourcel] = take > notTake?take : notTake;
return dp[item][resourcel];
}
}
int main(){
int tc,dummy, sum =0;
//freopen("in.txt","r",stdin);
scanf("%d",&tc);
for(int i = 0 ; i < tc; i++){
sum = 0;
memset(dp,-1,sizeof(dp));
scanf("%d",&n);
//cout<<" n is : "<<n<<endl;
for(int j = 0 ; j < n ;j++){
scanf("%d %d",&p[j],&w[j]);
//cout<<" price and val is : "<<p[j]<<" " << w[j]<<endl;
}
scanf("%d",&g);
//cout<<"g is : "<<g<<endl;
for(int p = 0 ; p< g;p++){
scanf("%d",&dummy);
sum+= knapsack(dummy,0);//wight allowed and item visited
}
printf("%d\n",sum);
}
return 0;
}
Your knapsack code is overly complicated. Here is another way to do it:
Let dp[i] = maximum profit we can get for weight i.
for i = 1 to numItems do
for j = knapsackWeight down to items[i].weight do
dp[j] = max(dp[j], dp[j - items[i].weight] + items[i].profit)
Now, you also want a field item.copies. We can simply add another loop in the middle to iterate this many times.
for i = 1 to numItems do
for k = 1 to items[i].copies do
for j = knapsackWeight down to items[i].weight do
dp[j] = max(dp[j], dp[j - items[i].weight] + items[i].profit)