#include <algorithm>
#include <functional>
#include <iostream>
#include <stack>
#include <string>
#include <vector>
#include <iterator>

using namespace std;
using namespace std::placeholders;

#define IT(v) (v).begin(), (v).end()

template <class Iterator>
void print_it(Iterator vbegin, Iterator vend) {
	if (vbegin == vend) return;
	cout << *vbegin;
	for (auto v = vbegin + 1; v!= vend; ++v) {
		cout << ", " <<  *v;
	}
	cout << endl;
}

template <class Iterator1, class Iterator2, class F>
auto zip_with(Iterator1 vbegin, Iterator1 vend, 
		Iterator2 wbegin, Iterator2 wend,
		F f) -> vector<decltype(f(*vbegin, *wbegin))> {
	vector<decltype(f(*vbegin, *wbegin))> r {};
	Iterator1 v = vbegin;
	Iterator2 w = wbegin;
	for (; v != vend && w != wend; ++v, ++w) {
		r.push_back(f(*v, *w));
	}
	return r;
}

struct Process {
	string name;
	vector<int> allocation;
	vector<int> max;
	bool can_allocate(const vector<int>& available) const;
	vector<int> unallocate(const vector<int>& available) const;
};

bool operator==(const Process& lhs, const Process& rhs) {
	return lhs.name == rhs.name 
		&& lhs.allocation == rhs.allocation
		&& lhs.max == rhs.max;
}

struct DfsData {
	vector<int> available;
	vector<Process> processes;
};

bool Process::can_allocate(const vector<int>& available) const {
	auto need = zip_with(IT(max), IT(allocation), minus<int>());
	auto test = zip_with(IT(need), IT(available), less_equal<int>());
	return all_of(IT(test), [](bool b) { return b; });
}

vector<int> Process::unallocate(const vector<int>& available) const {
	return zip_with(IT(available), IT(allocation), plus<int>());
}

vector<Process> solve_bankers(
		vector<int> available,
		vector<Process> processes) {
	stack<DfsData> s;
	s.push({
		.available = available,
		.processes = {}
	});
	while(!s.empty()) {
		DfsData d = s.top();
		s.pop();
		if (processes.size() == d.processes.size()) {
			return d.processes;
		}
		for (const auto&  p : processes) {
			if (d.processes.end() == std::find(IT(d.processes), p)
					&& p.can_allocate(d.available)) {
				vector<Process> ps (d.processes);
				ps.push_back(p);
				s.push({
					.available = p.unallocate(d.available),
					.processes = ps,
				});
			}
		}
	}
	return {};
}

int main() {
	vector<int> available {3,3,2};
	vector<Process> processes {
		{.name = "P0", .allocation = {0,1,0}, .max = {7,5,3}},
		{.name = "P1", .allocation = {2,0,0}, .max = {3,2,2}},
		{.name = "P2", .allocation = {3,0,2}, .max = {9,0,2}},
		{.name = "P3", .allocation = {2,1,1}, .max = {2,2,2}},
		{.name = "P4", .allocation = {0,0,2}, .max = {4,3,3}},
	};

	auto solution = solve_bankers(available, processes);
	vector<string> names {};
	for (auto& s : solution) {
		names.push_back(s.name);
	}
	print_it(IT(names));

	return 0;
}