Problema con shopping 60/100

Sto provando a risolvere il problema compulsive shopping solo che non riesco a capire a come applicare correttamente la programmazione dinamica. All’inizio ho tentato un approccio top down con memoizzazione (con l’utilizzo di una map), poi a causa della poca memoria e di diversi timeout sono passato ad una bottom up. Grazie a due array (uno contiene il risultato per un certo n escludendo l’iesimo numero l’altro includendolo) sono “riuscito” a calcolare il numero massimo di soldi rimanenti partendo da un budget E. Questo mi richiede una complessità O(n). Ho difficoltà nel capire come calcolare efficientemente invece il numero di soldi da sprecare prima di acquistare i diversi prodotti. Qualche consiglio?
Questo è il codice:

#include<bits/stdc++.h>
using namespace std;
ifstream fin("input.txt");
ofstream fout("output.txt");
int shopping(vector<int> &p, vector<int> &memoA, vector<int> &memoB, int n, int e)
{
	bool flag=false;
	if(e>=p[0]){
		memoA[0]=e-p[0];
		memoB[0]=e-p[0];
	}
	else{
		memoA[0]=e;
		memoB[0]=e;
		flag=true;
	}
	for(int i=1;i<n;++i){
		if(flag&&(memoB[i-1]>=p[i]||memoA[i-1]>=p[i])){
			memoB[i]=max(memoA[i-1]-p[i], memoB[i-1]-p[i]);
			if(memoA[i-1]>=p[i])
				memoA[i]=memoA[i-1]-p[i];
			else
				memoA[i]=memoA[i-1];
			flag=false;
		}
		else if((memoB[i-1]>=p[i]||memoA[i-1]>=p[i])){
			memoA[i]=memoB[i-1];
			memoB[i]=max(memoA[i-1]-p[i], memoB[i-1]-p[i]);
			flag=false;
		}
		else{
			memoA[i]=memoA[i-1];
			memoB[i]=memoB[i-1];
			flag=true;
		}
	}
	return max(memoA[n-1], memoB[n-1]);
}
int main()
{
	int n, e, res=0;
	fin>>n>>e;
	vector<int> price(n);
	vector<int> memoA(n);
	vector<int> memoB(n);
	for(int i=0;i<n;++i)
		fin>>price[i];
	/*cout<<shopping(price, memoA, memoB, n, e)<<"\n";
	for(int i=0;i<n;++i)
		cout<<memoA[i]<<" ";
	cout<<"\n";*/
	for(int i=e;i>res;--i)
		res=max(res, shopping(price, memoA, memoB, n, i));
	fout<<max(res, shopping(price, memoA, memoB, n, e))<<"\n";
 return 0;
}

L’osservazione fondamentale è che se arrivo ad un certo articolo P_i con certo budget E_i posso fare due cose:

  • acquistare l’articolo ottentendo un budget di E_i - P_i euro,
  • sprecare prima della camminata abbastanza soldi in modo da ottenere un budget di P_i - 1 soldi quando arrivo a tale articolo non potendolo perciò comprare.

Ciò riflettuto un po’ e non mi sono chiare diverse cose.

  1. Arrivato ad un certo articolo non c’è anche una terza cosa che posso fare? Ossia non acquistare l’articolo se ho acquistato il precedente.

  2. Come faccio a capire se è possibile arrivare ad un certo articolo con un budget Pi -1. Come faccio ad essere sicuro che affinchè ci arrivi il budget iniziale sia minore di E. Per esempio se ho:
    3 35
    20 35 10
    Arrivato all’articolo 35 potrei non comprarlo arrivandoci con un budget di 34 però per fare ciò dovrei avere un budget iniziale di 54 ma ciò non può essere fatto perchè quello iniziale in input è 35.

Non devi basarti sul budget iniziale ma solo sui valori del massimo budget possibile ottenuti per l’articolo precedente, proprio come nel tuo codice sopra. Se almeno uno tra memoA[i-1] e memoB[i-1] è maggiore o uguale a P_i allora è possibile ottenere un budget di P_i-1.

Sono riuscito a risolverlo grazie mille. Potresti consigliarmi dei problemi di programmazione dinamica da svolgere per prepararmi per le territoriali?

Il miglior problema su cui allenarsi è senza dubbio Festival del GCD anche se è un po’ difficile. Per altri problemi puoi cercare mediante il tag dp.