sono su sto problema da abbastanza tempo, ho provato un po’ di approcci ma si sono rivelati tutti sbagliati, per diversi motivi. Il primo è stato di tipo sorting and searching + programmazione dinamica, con questo codice:
#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct utenti{
ll prezzo;
ll film;
};
ll ind, biglietto;
vector<utenti> v;
void aggiorna(ll &budget, int i){
biglietto = v[i].prezzo;
budget -= v[i].film;
}
ll inzialize(ll &budget, int n){
while(v[ind].film > budget && ind < n) ind ++;
biglietto = v[ind].prezzo;
budget -= v[ind].film;
return v[ind].prezzo - v[ind].film;
}
ll bfs(int n, ll budget, vector<int> prezzi, vector<int> film){
v.resize(n);
vector<ll> dp;
for(int i = 0; i < n; i++){
v[i].prezzo = prezzi[i];
v[i].film = film[i];
}
sort(v.begin(), v.end(), [](utenti a, utenti b) {
if(a.prezzo - a.film == b.prezzo - b.film) return a.film < b.film;
return a.prezzo - a.film > b.prezzo - b.film;
});
if((v[0].prezzo - v[0].film) < 0) return 0;
dp.push_back(inzialize(budget, n));
if(ind == n) return 0;
for(int i = ind+1; i < n; i++){
if(v[i].prezzo - v[i].film <= 0) return dp.back();
if(v[i].film > budget) continue;
if(biglietto > v[i].prezzo){
ll guadagno = (dp.back() - (dp.size())*(biglietto - v[i].prezzo)) + (v[i].prezzo - v[i].film);
if(dp.back() < guadagno){
dp.push_back(guadagno);
aggiorna(budget, i);
}
}else{
dp.push_back(max(dp.back(), dp.back() + (biglietto - v[i].film)));
budget -= v[i].film;
}
}
return dp.back();
}
ma sono riuscito a fare solo 5/100 con errori di tipo “output not correct”, quindi non riuscivo sempre a trovare la soluzione ottima, tranne che in 27/71 testcase, di cui tutti i testcase del subtask 3.
Allora li ho capito c’è bisogno di controllare quasi tutte le possibili combinazioni di utenti per capire il prezzo del biglietto da impostare. Quindi ho pensato ad un approccio backtracking, ma ottimizzando qualcosina grazie all’ordinamento del vettore in base al prezzo, e qualche if che taglia un po’ di rami dell’albero delle chiamate che la mia funzione fa. Il codice è questo:
#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
struct utenti{
ll prezzo;
ll film;
};
vector<utenti> v;
ll best = 0;
void backtracking(ll spese, ll budget, int n, ll income = 0, int taken = 0){
//cout<<"spese:"<<spese<<" | n:"<<n<<" | income:"<<income<<" | taken:"<<taken<<endl;
if(n < 0){
if(spese <= budget) best = max(best, income - spese);
return;
}
if(spese + v[n].film > budget) best = max(best, income - spese);
else backtracking(spese + v[n].film, budget, n-1, v[n].prezzo * (taken + 1), taken+1);
backtracking(spese, budget, n-1, income, taken);
return;
}
ll bfs(int n, ll b, vector<int> p, vector<int> f){
for(int i = 0; i < n; i++){
if(p[i] - f[i] <= 0) continue;
if(f[i] > b) continue;
v.push_back({p[i], f[i]});
}
sort(v.begin(), v.end(), [](utenti a, utenti b){return a.prezzo < b.prezzo;});
backtracking(0, b, v.size()-1);
return best;
}
/*int main(){
int n;
ll q;
cin >> n >> q;
vector<int> p(n), f(n);
for(int i = 0; i < n; i++) cin >> p[i];
for(int i = 0; i < n; i++) cin >> f[i];
cout<<bfs(n, q, p, f);
}*/
Anche se l’approccio è backtracking ho fatto un algoritmo molto poco elegante, però si dovrebbe capire un minimo la solita questione: “ogni volta ho 2 possibilità: considerare l’untente o no”. Solo che in questo caso faccio 7/100 con 25/71 testcase, per errori di tipo “Execution timed out” che ci può stare visto la complessità, però di questo passo non so proprio come poter ottimizzare la ricerca. è l’approccio sbagliato oppure si può ottimizzare ancora? Mi manca qualche tecnica avanzata da studiare?