zeyad_alaa's blog

By zeyad_alaa, history, 9 months ago, In English

Hello so this is my first blog, I solved knapsack 1 but cant find any solution to solve V2 : https://atcoder.jp/contests/dp/tasks/dp_e

can any one help me ?

 
 
 
 
  • Vote: I like it
  • +20
  • Vote: I do not like it

»
9 months ago, # |
Rev. 2   Vote: I like it +2 Vote: I do not like it

first you have to find value per weight,then you sort them in descending order. then take one by one

  • »
    »
    7 months ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    this didn't work for me. It gave correct answer for a few cases, but then it failed 3/4th of the cases.

    Could you explain why?

»
9 months ago, # |
  Vote: I like it +10 Vote: I do not like it

This is a variant of the classic knapsack.

Notice that value is small (at most $$$10^5$$$ for all $$$100$$$ items), so instead of "what is the most value we can carry with weight $$$W$$$", you find "what is the least weight you need to carry to get a value of $$$V$$$".

  • »
    »
    6 weeks ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    Can it be done using top-down approach?

    • »
      »
      »
      6 weeks ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      I don't see why not :)

      The parameters are (the item we are considering, the value we have taken so far) for $$$100*10^5$$$ states. The choices for each state are still "take the item" and "ignore the item", just like in usual knapsack.

      Maybe memory limit might be an issue, but I've never had problems with $$$10^7$$$ integer states.

      • »
        »
        »
        »
        5 weeks ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

        Can't seem to figure it out! If I include the element, I add its weight. And when I don't include the element, I don't add its weight. I have to take the minimum of both the choices. What will be the base case? When I reach the end of the array, I simply return 0.

        public static int solve2(int n, int w, int[][] arr, int maxV) {
        		dp=new int[n+1][maxV+1];
        		for(int[] row:dp) {
        			Arrays.fill(row, Integer.MAX_VALUE);
        			
        		}
        		
        		solveMemo(arr,0,0);
        		for(int i=maxV;i>-1;--i) {
        			if(dp[n-1][maxV]<=w) {
        				return i;
        			}
        		}
        		
        		return 0;
        
        	}
        	
        	static int[][] dp;
        	
        	public static int solveMemo(int[][] arr, int maxV,int idx) {
        		if(idx==arr.length) {
        			return 0;
        		}
        		
        		if(dp[idx][maxV]!=Integer.MAX_VALUE) {
        			return dp[idx][maxV];
        		}
        		
        		int include = arr[idx][0] + solveMemo(arr,maxV+arr[idx][1],idx+1);
        		int not = solveMemo(arr,maxV,idx+1);
        		
        		
        		return dp[idx][maxV]=Math.min(include, not);
        	}
        

        But it doesn't seem to work! I also seem to understand while writing that it won't work. Where is it wrong and how do I make it work?

        • »
          »
          »
          »
          »
          5 weeks ago, # ^ |
            Vote: I like it 0 Vote: I do not like it

          Recurrence looks ok to me :) But there are some issues in solve2 I think.

          int only holds up to $$$2^{31} - 1$$$, so it should overflow.

          Also in this if else

          if(dp[n-1][maxV]<=w) {
          	return i;
          }
          

          Shouldn't it be more like this?

          if(dp[n-1][i]<=w) {
          	return i;
          }
          
          • »
            »
            »
            »
            »
            »
            5 weeks ago, # ^ |
            Rev. 2   Vote: I like it 0 Vote: I do not like it

            Fixed the solve2 method and overflow. Still doesn't give the correct answer. There's some issue in the recursion. Take case:

            6 15
            6 5
            5 6
            6 4
            6 6
            3 5
            7 2
            

            while calling recursion, at first, it goes on to include all elements, that is the first call, and then hits the base case from where it returns zero. Then the second call i.e. the not include case is called for the last element, from where it gets 0 from the base case. Now dp[n-1][maxV-valueOfLastElement]=0 because of the not include case. Isn't this wrong because it says to get value of [maxV-valueOfLastElement], we need only 0 weight. It didn't add up the weights of previously selected elements.

            • »
              »
              »
              »
              »
              »
              »
              5 weeks ago, # ^ |
              Rev. 2   Vote: I like it 0 Vote: I do not like it

              Yeah looks like we missed that part :)

              I guess we're both messing up the definitions a bit here. Usually we define dp(i, V) as "first i items, we are allowed to take V more values". So the answer should be dp(N, initialV), and the recurrence actually goes backwards from $$$N$$$ to $$$0$$$ (and likewise, from $$$maxV$$$ to $$$0$$$).

              So you can implement the same recurrence but backwards (i.e. "if I include the element, I decrease $$$maxV$$$"), and do

              for(int i = maxV;i>-1;--i) {
              	if (solve(arr, N, i) <= w) {
              		return i;
              	}
              }
              
»
9 months ago, # |
  Vote: I like it +2 Vote: I do not like it

You may consider iterating over sum of values rather than weights as per the constraints..So making the definition of dp[i] as minimum weight that can be taken with exactly i value..you can iterate on items and value(since constraints on value is low) My submission..https://atcoder.jp/contests/dp/submissions/10848260 ..Also you can refer to Youtube video by Errichto for the same

»
9 months ago, # |
  Vote: I like it +8 Vote: I do not like it

MidoriFuse dark__forest thanks guys, that helped me

»
9 months ago, # |
  Vote: I like it +5 Vote: I do not like it

An alternative is Branch and Bound algorithm. Don't simply look at its theoretical time complexity. It works wonders in practice.

»
9 months ago, # |
Rev. 2   Vote: I like it 0 Vote: I do not like it

You can try Branch and Bound to run faster

Spoiler
  • »
    »
    9 months ago, # ^ |
    Rev. 3   Vote: I like it +4 Vote: I do not like it

    It should be noted that the Branch and Bound algorithm doesn't always run fast. It's runtime depends on the accuracy and speed of the cost-estimation function. The better the cost-estimation function, the faster your answer will attain the optimum value. In this case, the cost-estimation function is both good and fast, so Branch and Bound works.

    p.s. I don't think you understand how Branch and Bound works. It seems to me that your code uses DP instead of Branch and Bound.

    • »
      »
      »
      9 months ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      Yes. Thank you for reminding me. Since I always adding Branch and Bound for faster in some specific problems, I forgot to notice that not at every time it work faster than normal approach

    • »
      »
      »
      7 months ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      Yeah it is Top Down DP !!

»
7 months ago, # |
  Vote: I like it 0 Vote: I do not like it
»
7 months ago, # |
  Vote: I like it 0 Vote: I do not like it

This helped me.

»
7 months ago, # |
Rev. 2   Vote: I like it 0 Vote: I do not like it

How to solve Knapsack-2 in single-d array? Anyone? This is my code and i am really stuck.

#include <iostream>
#include<vector>
using namespace std;

int main() {
   int  n,w,gmax=0;
   cin>>n>>w;
   vector<int> weights(n,0),values(n,0);

   for(int i=0;i<n;i++)
    cin>>weights[i]>>values[i];

   vector<long long int> dp(100001);

   for(int i=0;i<=n;i++)
   {
       for(int j=0;j<100001;j++)
       {

           if(j==0)
           {
               dp[j]=0;
               continue;
           }

           if(i==0)
           {
               dp[j]=w+1;
               continue;
           }

           if(values[i-1]<=j)
           {
               dp[j]=min(weights[i-1]+dp[j-values[i-1]],dp[j]);
           }
       }
   }
    
    for(int j=0;j<100001;j++)
       {
           if(dp[j]<=w)
            gmax=max(gmax,j);
       }

   cout<<gmax;

   return 0;
}

  • »
    »
    7 months ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    Please put codes in spoilers. Your code is incorrect because You do not know if $$$dp[j-values[i-1]]$$$ has already used your current object and you may use it again. To fix that, you may iterate $$$j$$$ in reverse, so you know for a fact $$$dp[j-value[i-1]]$$$ is untouched.

»
7 months ago, # |
  Vote: I like it 0 Vote: I do not like it

Refer to this solution in which I have explained Knapsnack 0-1 with all possible implementation 1. Recursive Memoisation 2. Tabulation: space O(n^2) 3. Tabulation: space O(n) 4. The special case when max capacity is large, done using tabulation.

»
6 months ago, # |
  Vote: I like it 0 Vote: I do not like it
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<long,long> pl;
typedef pair<ll,ll> pll;
typedef vector<long> vl;
typedef vector<bool> vb;
typedef vector<ll> vll;
typedef vector<vl> vvl;
typedef vector<vb> vvb;
typedef vector<vll> vvll;
typedef vector<pll> vpll;
typedef vector<string> vs;

#define FOR(i,a,b) for(long long i=a;i<b;++i)
#define REV(i,a,b) for(long long i=a;i>=b;i--)
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define ub upper_bound
#define lb lower_bound
#define all(v) v.begin(),v.end()
#define tc ll t;cin>>t;while(t--)
#define io ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define coutv(v) for(auto it: (v))cout<<it<<" ";newl;
#define cout2d(v) for(auto it: (v)) {for(auto j:it) cout<<j<<" ";newl;}
#define cinv(v,n) vll (v)(n);FOR(i,0,(n)){cin>>v[i];}
#define cinvg(v,n) (v).resize(n);FOR(i,0,(n)){cin>>v[i];}
#define cin2d(v,n,m) vvll (v)(n,vll(m,0));FOR(i,0,n){FOR(j,0,m){cin>>v[i][j];}}
#define cin2dg(v,n,m) (v).resize(n,vll(m));FOR(i,0,n){FOR(j,0,m){cin>>v[i][j];}}
#define newl cout<<"\n"
#define mod 1000000007
#define INF 1e18

int main()
{
	io;
	ll n,W,V=0,ans=-1;
	cin>>n>>W;
	vll w(n+1),v(n+1);
	FOR(i,1,n+1)
	{
		cin>>w[i]>>v[i];
		V+=v[i];
	}
	
	vvll dp(n+1,vll(V+1,INF));
	dp[0][0]=0;
	FOR(i,0,V+1)
	{
		dp[0][i]=0;
	}
	
	FOR(i,1,n+1)
	{
		FOR(j,1,V+1)
		{
			dp[i][j]=dp[i-1][j];
			if(j-v[i]>=0){dp[i][j]=min(dp[i][j],dp[i-1][j-v[i]]+w[i]);}
		}
	}
	
	REV(i,V,1)
	{
		if(dp[n][i]<=W){ans=max(ans,i);}
	}
	cout<<ans;
	return 0;
}

Can someone tell me what is wrong with this. I am unable to see the initialisation