Cod sursa(job #3254986)

Utilizator amcbnCiobanu Andrei Mihai amcbn Data 9 noiembrie 2024 11:03:51
Problema Problema rucsacului Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.35 kb
#include <bits/stdc++.h>
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
ifstream fin("rucsac.in");
ofstream fout("rucsac.out");

const int nmax = 10000;
int n;
long long W;
pair<long long, long long> a[nmax + 5];
pair<long long, long long> pref[nmax + 5];

long long weight = 0;
long long profit = 0;
long long max_profit = -1;

// 2. euristica optimista dar mai aproape de realitate - daca solutia curenta + solutia optimista pentru sufixul ramas
// tot e mai mica decat profixul maxim, nu are sensa sa continuam
inline long double bestSuffixProfit(int i, long long remaining_weight) {
	long double best_profit = 0;
	for (int j = i; j <= n && remaining_weight > 0; ++j) {
		long long aux = min(remaining_weight, a[j].first);
		remaining_weight -= aux;
		best_profit += 1.0 * a[j].second * aux / a[j].first;
	}
	return best_profit;
}

inline void take(int i) {
	weight += a[i].first;
	profit += a[i].second;
}

inline void untake(int i) {
	weight -= a[i].first;
	profit -= a[i].second;
}

void backtrack(int i) {
	if (i > n) {
		if (profit > max_profit) {
			max_profit = profit;
		}
		return;
	}
	if (profit + bestSuffixProfit(i, W - weight) <= max_profit) {
		return;
	}
	// 4. preferam sa luam obiectele decat sa nu le luam
	// il luam
	take(i);
	if (weight <= W) { // 1. greutatea curenta nu trebuie sa depaseasca greutatea maxima
		backtrack(i + 1);
	}
	untake(i);
	// nu il luam
	backtrack(i + 1);
}

long long greedySolution() {
	long long current_weight = 0;
	long long current_profit = 0;
	for (int i = 1; i <= n; ++i) {
		if (current_weight + a[i].first > W) {
			break;
		}
		current_weight += a[i].first;
		current_profit += a[i].second;
	}
	return current_profit;
}

int main() {
	fin >> n >> W;
	for (int i = 1; i <= n; ++i) {
		fin >> a[i].first >> a[i].second;
	}
	// sortam dupa raportul p[i] / w[i] 
	sort(a + 1, a + n + 1, [&](const pair<int, int>& lhs, const pair<int, int>& rhs) {
		return 1ll * lhs.second * rhs.first > 1ll * rhs.second * lhs.first;
		});
	// facem sume partiale pe w[] si p[]
	for (int i = 1; i <= n; ++i) {
		pref[i].first = pref[i - 1].first + a[i].first;
		pref[i].second = pref[i - 1].second + a[i].second;
	}
	// 3. pornim de la o solutie buna destul de optima
	max_profit = greedySolution();
	backtrack(1);
	fout << max_profit;
}