Accepted date: 2011-03-12
Ranking (as of 2013-10-26): 178 out of 817
Language: C++
Used sort of an incomplete Dynamic Programming to get the candidates of solutions and then
Applied backtracking for the candidates.
/*
8.6.5 Tug of War
PC/UVa IDs: 110805/10032, Popularity: B, Success rate: low Level: 2
To build using Visucal Studio 2008:
cl -EHsc tug_of_war.cpp
*/
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#ifdef __ELAPSED_TIME__
#include <ctime>
#endif
using namespace std;
#ifdef DEBUG
void print_pr_people(int sum_of_weights, const vector< pair<unsigned char,
unsigned char> >& nr_people)
{
for (int i = 1; i <= sum_of_weights; i++)
if (nr_people[i].first)
cout << i << '(' << static_cast<unsigned int>(nr_people[i].first) << ' ' <<
static_cast<unsigned int>(nr_people[i].second) << ") ";
cout << endl;
}
#endif
int generate_nr_people(int n, const vector<int>& weights,
vector< pair<unsigned char, unsigned char> >& nr_people)
{
/*
While calculating each realizable team weight,
also record the minimum/maximum number of people whose weights are
added up to it.
*/
int sum_of_weights = 0;
for (int i = 1; i <= n; i++) {
int w = weights[i];
for (int j = sum_of_weights; j; j--)
if (nr_people[j].first) {
if (nr_people[j + w].first) {
nr_people[j + w].first = min(nr_people[j + w].first,
static_cast<unsigned char>(nr_people[j].first + 1));
nr_people[j + w].second = max(nr_people[j + w].second,
static_cast<unsigned char>(nr_people[j].second + 1));
}
else {
nr_people[j + w].first = nr_people[j].first + 1;
nr_people[j + w].second = nr_people[j].second + 1;
}
}
nr_people[w].first = 1;
if (!nr_people[w].second)
nr_people[w].second = 1;
sum_of_weights += w;
}
#ifdef DEBUG
print_pr_people(sum_of_weights, nr_people);
#endif
return sum_of_weights;
}
bool is_valid_team_weight(int nr_one, int nr_other,
int one_weight, int other_weight, int nr_weights,
const vector<int>& weights, const vector< pair<unsigned char,
unsigned char> >& nr_people)
{
if (!nr_weights)
return false;
int w = one_weight - weights[nr_weights];
if (!w) {
if (nr_one == 1)
return true;
else if (nr_other > 1 && other_weight == one_weight)
return false;
else return is_valid_team_weight(nr_other, nr_one, other_weight, one_weight,
nr_weights, weights, nr_people);
}
else if (w < 0)
return is_valid_team_weight(nr_other, nr_one, other_weight, one_weight,
nr_weights, weights, nr_people);
else if (nr_people[w].first && nr_one - 1 >= nr_people[w].first &&
nr_one - 1 <= nr_people[w].second &&
is_valid_team_weight(nr_one - 1, nr_other, w, other_weight,
nr_weights - 1, weights, nr_people))
return true;
else {
if (!(w = other_weight - weights[nr_weights]))
return (nr_other == 1) ? true : false;
else if (w < 0)
return false;
else if (nr_people[w].first && nr_other - 1 >= nr_people[w].first &&
nr_other - 1 <= nr_people[w].second &&
is_valid_team_weight(nr_one, nr_other - 1, one_weight, w,
nr_weights - 1, weights, nr_people))
return true;
else
return false;
}
}
pair<int, int> find_minimum_team_weight_pair(int n, int sum_of_weights,
const vector<int>& weights, const vector< pair<unsigned char,
unsigned char> >& nr_people)
{
int nr_one_max = n / 2, nr_other_max = 0; // max. number of people for a team
if (n & 1)
nr_other_max = nr_one_max + 1;
int i = sum_of_weights / 2;
for ( ; ; i--) {
int nr_one = nr_people[i].first, nr_other =
nr_people[sum_of_weights - i].first;
if (nr_one && nr_other) {
if (n & 1) {
if (nr_one < nr_other_max && nr_other < nr_other_max) {
if (is_valid_team_weight(nr_other_max, nr_one_max, sum_of_weights - i,
i, n, weights, nr_people) ||
is_valid_team_weight(nr_other_max, nr_one_max, i, sum_of_weights - i,
n, weights, nr_people))
break;
}
else if (nr_one == nr_other_max) {
if (is_valid_team_weight(nr_other_max, nr_one_max, i,
sum_of_weights - i, n, weights, nr_people))
break;
}
else if (nr_other == nr_other_max) {
if (is_valid_team_weight(nr_other_max, nr_one_max, sum_of_weights - i,
i, n, weights, nr_people))
break;
}
}
else {
if (nr_one <= nr_one_max && nr_other <= nr_one_max) {
if (is_valid_team_weight(nr_one_max, nr_one_max, sum_of_weights - i,
i, n, weights, nr_people) ||
is_valid_team_weight(nr_one_max, nr_one_max, i, sum_of_weights - i,
n, weights, nr_people))
break;
}
}
}
}
return make_pair(i, sum_of_weights - i);
}
int main(int /* argc */, char** /* argv */)
{
#ifdef __ELAPSED_TIME__
clock_t start = clock();
#endif
int cases; // number of test cases
cin >> cases;
while (cases--) {
int n;
cin >> n; // number of people
vector<int> weights(n + 1); // vector of weights
weights[0] = 0;
for (int i = 1; i <= n; i++)
cin >> weights[i];
if (n < 2)
cout << "0 " << weights[n] << endl;
else {
sort(weights.begin() + 1, weights.end());
int sum_of_weights = 0;
for (int i = 1; i <= n; i++)
sum_of_weights += weights[i];
vector< pair<unsigned char, unsigned char> >
nr_people(sum_of_weights + 1, make_pair(0, 0));
// nr_peoplei].first/second is the minimum/maximum number of people
// whose weights are added up to i, or 0 if no weights are added up to i
generate_nr_people(n, weights, nr_people);
pair<int, int> weight_pair =
find_minimum_team_weight_pair(n, sum_of_weights, weights, nr_people);
cout << weight_pair.first << ' ' << weight_pair.second << endl;
}
if (cases)
cout << endl;
// the output of each two consecutive cases will be separated
// by a blank line
}
#ifdef __ELAPSED_TIME__
cerr << "elapsed time = " <<
static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
return 0;
}