Cod sursa(job #2121380)

Utilizator preda.andreiPreda Andrei preda.andrei Data 3 februarie 2018 17:12:52
Problema Ghiozdan Scor 50
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.5 kb
#include <algorithm>
#include <fstream>
#include <vector>

using namespace std;

struct Solution
{
  int total_weight;
  vector<int> weights;
};

struct Trace
{
  int weight;
  int count;
};

constexpr Trace kEmptyTrace = {0, 0};

constexpr int kMaxWeight = 75000;
constexpr int kInf = (1 << 25);

vector<int> GetPieceSizes(int count)
{
  vector<int> pieces;
  int power = 1;

  while (power <= count) {
    pieces.push_back(power);
    count -= power;
    power <<= 1;
  }

  if (count > 0) {
    pieces.push_back(count);
  }
  return pieces;
}

void AddObject(int weight, int count, vector<int> &cost, vector<Trace> &trace)
{
  auto total_weight = weight * count;
  auto start = cost.size() - total_weight - 1;

  for (int i = start; i >= 0; --i) {
    if (cost[i] >= kInf) {
      continue;
    }

    auto new_weight = i + total_weight;
    auto new_cost = cost[i] + count;

    if (new_cost < cost[new_weight]) {
      cost[new_weight] = new_cost;
      trace[new_weight].weight = weight;
      trace[new_weight].count = count;
    }
  }
}

void FindCosts(const vector<int> &obj, vector<int> &cost, vector<Trace> &trace)
{
  fill(cost.begin(), cost.end(), kInf);
  cost[0] = 0;

  fill(trace.begin(), trace.end(), kEmptyTrace);

  for (size_t i = 1; i < obj.size(); ++i) {
    if (obj[i] <= 0) {
      continue;
    }

    auto sizes = GetPieceSizes(obj[i]);
    for (const auto &size : sizes) {
      AddObject(i, size, cost, trace);
    }
  }
}

vector<int> Reconstruct(const vector<Trace> &trace, int weight)
{
  vector<int> weights;
  while (weight > 0) {
    auto count = trace[weight].count;
    auto added = trace[weight].weight;

    for (int i = 0; i < count; ++i) {
      weights.push_back(added);
    }
    weight -= count * added;
  }
  return weights;
}

Solution Solve(const vector<int> &obj, int cap)
{
  vector<int> cost(cap + 1);
  vector<Trace> trace(cap + 1);
  FindCosts(obj, cost, trace);

  auto max_weight = cap;
  while (max_weight > 0 && cost[max_weight] >= kInf) {
    max_weight -= 1;
  }

  auto weights = Reconstruct(trace, max_weight);
  return {max_weight, weights};
}

int main()
{
  ifstream fin("ghiozdan.in");
  ofstream fout("ghiozdan.out");

  int n, capacity;
  fin >> n >> capacity;

  vector<int> objects(kMaxWeight + 1, 0);
  for (int i = 0; i < n; ++i) {
    int weight;
    fin >> weight;
    objects[weight] += 1;
  }

  auto res = Solve(objects, capacity);
  fout << res.total_weight << " " << res.weights.size() << "\n";

  for (const auto &weight : res.weights) {
    fout << weight << "\n";
  }
  return 0;
}