Code Jam 2008 "Price Is Wrong" - Explanation - algorithm

I have been going through Code Jam archives. I am really struggling at the solution of The Price Is Wrong of Code Jam 2008
The problem statement is -
You're playing a game in which you try to guess the correct retail price of various products for sale. After guessing the price of each product in a list, you are shown the same list of products sorted by their actual prices, from least to most expensive. (No two products cost the same amount.) Based on this ordering, you are given a single chance to change one or more of your guesses.
Your program should output the smallest set of products such that, if you change your prices for those products, the ordering of your guesses will be consistent with the correct ordering of the product list. The products in the returned set should be listed in alphabetical order. If there are multiple smallest sets, output the set which occurs first lexicographically.
For example, assume these are your initial guesses:
code = $20
jam = $15
foo = $40
bar = $30
google = $60
If the correct ordering is code jam foo bar google, then you would need to change two of your prices in order to match the correct ordering. You might change one guess to read jam = $30 and another guess to read bar = $50, which would match the correct ordering and produce the output set bar jam. However, the output set bar code comes before bar jam lexicographically, and you can match the correct ordering by changing your guesses for these items as well.
Example
Input
code jam foo bar google
20 15 40 30 60
Output
Case #1: bar code
I am not asking for exact solution but for, how should I proceed with the problem
Thanks in advance.

Okay after struggling a bit, I got both small & large cases accepted.
Before posting my ugly ugly code, here is some brief explanation:
First, based on the problem statement, and the limits of the parameters, it is intuitive to think that the core part of the problem is simply finding Longest Increasing Subsequence (LIS). It does rely on your experience to figure it out fast though (indeed most cases in competitive programming field).
Think like this, if I can find the set of items which price is forming a LIS, then the items left are the smallest set that you need to change.
But you need to fulfil one more requirement, which is I think is the hardest part of this problem, is when there exists multiple smallest set, you have to find the lexicographical smallest one. That is same as saying find the LIS with lexicographical largest name (and then we throw them away, the items left is the answer)
To do this, there are many ways, but as the limits are so small (N <= 64), you can use basically whatever algorithm (O(N^4)? O(N^5)? Go ahead!)
My accepted method is to add a stupid twist into the traditional O(N^2) dynamic programming for LIS:
Let DP(i) be the LIS in number[0..i] AND number i must be chosen
Also use an array of set<string> to store the optimal set of items'name which can achieve DP(i), we update this array together with the process of doing dynamic programming for finding DP(i)
Then after the dynamic programming, simply find the lexicographical largest set of item's name, and exclude them from the original item set. The items left is the answer.
Here is my accepted ugly ugly code in C++14, most of the lines is to handle the troublesome I/O stuff, please tell me if it's not clear, I can provide a few example to elaborate more.
#include<bits/stdc++.h>
using namespace std;
int T, n, a[70], dp[70], mx=0;
vector<string> name;
set<string> ans, dp2[70];
string s;
char c;
bool compSet(set<string> st1, set<string> st2){
if(st1.size() != st2.size()) return true;
auto it1 = st1.begin();
auto it2 = st2.begin();
for(; it1 != st1.end(); it1++, it2++)
if((*it1) > (*it2)) return true;
else if((*it1) < (*it2)) return false;
return false;
}
int main() {
cin >> T;
getchar();
for(int qwe=1;qwe<=T;qwe++){
mx=n=0; s=""; ans.clear(); name.clear();
while(c=getchar(), c != '\n'){
if(c == ' ') n++, name.push_back(s), ans.insert(s),s="";
else s+=c;
}
name.push_back(s); ans.insert(s); s=""; n++;
for(int i=0; i<n; i++) cin >> a[i];
getchar();
for(int i=0 ;i<n;i++)
dp[i] = 1, dp2[i].clear(), dp2[i].insert(name[i]);
for(int i=1; i<n; i++){
for(int j=0; j<i;j++){
if(a[j] < a[i] && dp[j]+1 >= dp[i]){
dp[i] = dp[j]+1;
set<string> tmp = dp2[j];
tmp.insert(name[i]);
if(compSet(tmp, dp2[i])) dp2[i] = tmp;
}
}
mx = max(mx, dp[i]);
}
set<string> tmp;
for(int i=0; i<n; i++) {
if(dp[i] == mx) if(compSet(dp2[i], tmp)) tmp = dp2[i];
}
for(auto x : tmp)
ans.erase(x);
printf("Case #%d: ", qwe);
for(auto it = ans.begin(); it!=ans.end(); ){
cout << *it;
if(++it!= ans.end()) cout << ' ';
else cout << '\n';
}
}
return 0;
}

Well based on the problem you have specified, if i tell you that you don't need to tell me the order or name of the products, rather you just need to tell me -
The number of the product values that will change.
What would your answer be?
Basically then the problem has reduced to the following statement -
You are given a list of numbers and you want to make some changes to the list such that the numbers are now in increasing order. But you want your changes made to the individual elements of the list to be minimum.
How would you solve this?
If you find out the Longest Increasing Sub-sequence in the list of numbers you have, then you just need to subtract the length of the list from that LIS value.
Why you ask?
Well because if you want the number of changes made to the list to be minimum then if i leave the longest increasing sub-sequence as it is and change the other values i will definitely get the most optimal answer.
Let's take your example -
We have - 2 10 4 6 8
How many changes would be made to this list?
The longest increasing subsequence length is - 4.
So if we leave 4 item values as they are and change the other remaining values then we would only have to change 5(list length) - 4 = 1 values.
Now addressing your original problem, you need to print the product names. Well if you exclude the elements present in the LIS you should get your answer.
But wait!
What happens when you have many subsequences with the same LIS length? How will you choose the lexicographically smallest answer?
Well why don't you think about it in terms of LIS itself. This should be good enough to get you started right?

Related

How to get all combination of (numbers from a list) and (simple math operators)

Ok, so if you have a list of numbers (any size) like this:
[5, 7] (It's short so i can type all the combinations)
I want like a loop that returns a list of combinations like this:
5+7
5-7
5*7
5/7
7+5
7-5
7*5
7/5
I have thought about this for a while and I know it's structured in a tree diagram but i just don't know how to make it work for any size of list.
The easiest way would be to use recursive algorithm like:
combination(list)
for(numbers,operators)
combination_list+=number+operation+combination(rest)
return combination_list
you can do it by using iterative approach as well as any recursive algorithm has an iterative counterpart
A general solution
void operations(int[] numbers){
int size = //determine the number of elements in the array
for(int i=0; i < size; i++){
for (int j = 0; j < size;j++){
if( i !=j){
/*do all the operations
numbers[i] + numbers[j]
numbers[i] - numbers[j]
numbers[i] * numbers[j]
numbers[i] / numbers[j]
*/
}
}
}
}
A little about the combinatorics behind this first:
Generating all possible orderings of the integer list will be N! combinations, and onto each of those combinations then all of the possible selections of operators between them, [number of operators]^[number of gaps between integers], so 4^(n-1)
multiplying those two numbers together for the total number of listings you will have: N!*(4^(n-1))
Just adding a third integer to the list will get you 96 possible combinations, and a fourth for 1536, I'm sure you knew though this will grow really quickly.
(and I'm also ignoring the fact that if your list has duplicate integers you don't need to create duplicate permutations of that list, so all of the above only applies to a list of unique integers)
I think the way I would try this would be to first create a listing of all permutations of the N many integers and a listing of all of the N-1 many selections of operators separately. Then combining them into one much larger listing using a pair of foreach loops.
List<Integer[]> orderings = //a bunch of arrays each one being a unique ordering of all integers in the inital listing
List<Character[]> selections = //a bunch of arrays each one being a unique selection of the 4 operators
List<String> combinations = new ArrayList<String>();
for(Integer[] order : orderings) {
for(Character[] selection : selections) {
//now combine order (numbers) and selection(operators) alternating between indexes
String combination = order[0].toString();
for(int i = 0; i < selection.length; i++) {
combination += selection[i].toString() + order[i+1].toString();
}
combinations.add(combination);
}
}
generating the permutations of the numbers is like finding all the possible orderings for a deck of cards, it's a problem that should have many easily find-able solutions elsewhere on stack overflow, and finding all the selections of operators isn't much harder either.
Edit: Oh, I just realized that I'm not sure if you were specifically wanted only pairs of numbers, so a list of 3 numbers will only output pairings of any two integers, not orderings containing all 3, if it's just pairs of numbers then the problem gets a bit simpler.

Divvying people into rooms by last name?

I often teach large introductory programming classes (400 - 600 students) and when exam time comes around, we often have to split the class up into different rooms in order to make sure everyone has a seat for the exam.
To keep things logistically simple, I usually break the class apart by last name. For example, I might send students with last names A - H to one room, last name I - L to a second room, M - S to a third room, and T - Z to a fourth room.
The challenge in doing this is that the rooms often have wildly different capacities and it can be hard to find a way to segment the class in a way that causes everyone to fit. For example, suppose that the distribution of last names is (for simplicity) the following:
Last name starts with A: 25
Last name starts with B: 150
Last name starts with C: 200
Last name starts with D: 50
Suppose that I have rooms with capacities 350, 50, and 50. A greedy algorithm for finding a room assignment might be to sort the rooms into descending order of capacity, then try to fill in the rooms in that order. This, unfortunately, doesn't always work. For example, in this case, the right option is to put last name A in one room of size 50, last names B - C into the room of size 350, and last name D into another room of size 50. The greedy algorithm would put last names A and B into the 350-person room, then fail to find seats for everyone else.
It's easy to solve this problem by just trying all possible permutations of the room orderings and then running the greedy algorithm on each ordering. This will either find an assignment that works or report that none exists. However, I'm wondering if there is a more efficient way to do this, given that the number of rooms might be between 10 and 20 and checking all permutations might not be feasible.
To summarize, the formal problem statement is the following:
You are given a frequency histogram of the last names of the students in a class, along with a list of rooms and their capacities. Your goal is to divvy up the students by the first letter of their last name so that each room is assigned a contiguous block of letters and does not exceed its capacity.
Is there an efficient algorithm for this, or at least one that is efficient for reasonable room sizes?
EDIT: Many people have asked about the contiguous condition. The rules are
Each room should be assigned at most a block of contiguous letters, and
No letter should be assigned to two or more rooms.
For example, you could not put A - E, H - N, and P - Z into the same room. You could also not put A - C in one room and B - D in another.
Thanks!
It can be solved using some sort of DP solution on [m, 2^n] space, where m is number of letters (26 for english) and n is number of rooms. With m == 26 and n == 20 it will take about 100 MB of space and ~1 sec of time.
Below is solution I have just implemented in C# (it will successfully compile on C++ and Java too, just several minor changes will be needed):
int[] GetAssignments(int[] studentsPerLetter, int[] rooms)
{
int numberOfRooms = rooms.Length;
int numberOfLetters = studentsPerLetter.Length;
int roomSets = 1 << numberOfRooms; // 2 ^ (number of rooms)
int[,] map = new int[numberOfLetters + 1, roomSets];
for (int i = 0; i <= numberOfLetters; i++)
for (int j = 0; j < roomSets; j++)
map[i, j] = -2;
map[0, 0] = -1; // starting condition
for (int i = 0; i < numberOfLetters; i++)
for (int j = 0; j < roomSets; j++)
if (map[i, j] > -2)
{
for (int k = 0; k < numberOfRooms; k++)
if ((j & (1 << k)) == 0)
{
// this room is empty yet.
int roomCapacity = rooms[k];
int t = i;
for (; t < numberOfLetters && roomCapacity >= studentsPerLetter[t]; t++)
roomCapacity -= studentsPerLetter[t];
// marking next state as good, also specifying index of just occupied room
// - it will help to construct solution backwards.
map[t, j | (1 << k)] = k;
}
}
// Constructing solution.
int[] res = new int[numberOfLetters];
int lastIndex = numberOfLetters - 1;
for (int j = 0; j < roomSets; j++)
{
int roomMask = j;
while (map[lastIndex + 1, roomMask] > -1)
{
int lastRoom = map[lastIndex + 1, roomMask];
int roomCapacity = rooms[lastRoom];
for (; lastIndex >= 0 && roomCapacity >= studentsPerLetter[lastIndex]; lastIndex--)
{
res[lastIndex] = lastRoom;
roomCapacity -= studentsPerLetter[lastIndex];
}
roomMask ^= 1 << lastRoom; // Remove last room from set.
j = roomSets; // Over outer loop.
}
}
return lastIndex > -1 ? null : res;
}
Example from OP question:
int[] studentsPerLetter = { 25, 150, 200, 50 };
int[] rooms = { 350, 50, 50 };
int[] ans = GetAssignments(studentsPerLetter, rooms);
Answer will be:
2
0
0
1
Which indicates index of room for each of the student's last name letter. If assignment is not possible my solution will return null.
[Edit]
After thousands of auto generated tests my friend has found a bug in code which constructs solution backwards. It does not influence main algo, so fixing this bug will be an exercise to the reader.
The test case that reveals the bug is students = [13,75,21,49,3,12,27,7] and rooms = [6,82,89,6,56]. My solution return no answers, but actually there is an answer. Please note that first part of solution works properly, but answer construction part fails.
This problem is NP-Complete and thus there is no known polynomial time (aka efficient) solution for this (as long as people cannot prove P = NP). You can reduce an instance of knapsack or bin-packing problem to your problem to prove it is NP-complete.
To solve this you can use 0-1 knapsack problem. Here is how:
First pick the biggest classroom size and try to allocate as many group of students you can (using 0-1 knapsack), i.e equal to the size of the room. You are guaranteed not to split a group of student, as this is 0-1 knapsack. Once done, take the next biggest classroom and continue.
(You use any known heuristic to solve 0-1 knapsack problem.)
Here is the reduction --
You need to reduce a general instance of 0-1 knapsack to a specific instance of your problem.
So lets take a general instance of 0-1 knapsack. Lets take a sack whose weight is W and you have x_1, x_2, ... x_n groups and their corresponding weights are w_1, w_2, ... w_n.
Now the reduction --- this general instance is reduced to your problem as follows:
you have one classroom with seating capacity W. Each x_i (i \in (1,n)) is a group of students whose last alphabet begins with i and their number (aka size of group) is w_i.
Now you can prove if there is a solution of 0-1 knapsack problem, your problem has a solution...and the converse....also if there is no solution for 0-1 knapsack, then your problem have no solution, and vice versa.
Please remember the important thing of reduction -- general instance of a known NP-C problem to a specific instance of your problem.
Hope this helps :)
Here is an approach that should work reasonably well, given common assumptions about the distribution of last names by initial. Fill the rooms from smallest capacity to largest as compactly as possible within the constraints, with no backtracking.
It seems reasonable (to me at least) for the largest room to be listed last, as being for "everyone else" not already listed.
Is there any reason to make life so complicated? Why cann't you assign registration numbers to each student and then use the number to allocate them whatever the way you want :) You do not need to write a code, students are happy, everyone is happy.

How to find the best combination of many pieces of data depending on certain criteria?

I am trying to write a Python script that finds combinations of armor items from a game that match certain criteria. I have an object that has keys for each item slot (ie. head, chest, waist, etc.) and a list of all the items that can fit in that slot with their stats in each key. There are 10 slots and many items for each up to a total of 88 or so items.
My question is: Is there some kind of algorithm already used to do stuff like this? An example of what I would want to do is find the combination of armor pieces that gives me stat1 < 35 that has the highest stat2+3+4.
I don't believe brute forcing it would be practical because it would take ages (correct me if I'm wrong). Any help would be appreciated!
Edit - More details:
Data sample: http://pastebin.com/rTH3Q5Sj The first tuple is 2 head slot items, 2nd tuple is 2 chest slot items.
One thing I might want to do with the sample data is get the combination of helm and chest that has the highest slashing/bludgeoning/piercing total but less than 12 encumbrance total.
It sounds like the elegant solution to this is linear programming. I can help with that if you provide more details.
with only 88 items spread out amongst ten slots, brute forcing it wouldn't be terrible either. Some combination of the two might be the easiest.
update:
based on the update you gave, I think linear programming is overkill (and difficult to apply). I wrote you this fairly general solution. Study it and understand it. If anybody has any corrections or improvements, I'd love to hear them.
from itertools import ifilter, product
# Definition of ITEMS cut for brevity. See below.
def find_best(slots, maximize, constraints):
"""example call:
find_best(['helm', 'chest'], ['slashing', 'bludgeon'],
{'encumbrance': 12})
"""
# save the slot names to construct a nice return value
slot_names = slots
# pull the actual lists of items for each slot out of the global dict
slots = [ITEMS[slot] for slot in slots]
# this function calculates the value of a solution
value = lambda solution: sum(float(slot[attr]) for attr in maximize
for slot in solution)
# replace our constraints with functions to check solutions
constraints = [lambda solution:
sum(float(slot[attr]) for slot in solution) < constraint
for attr, limit in constraints.items()]
# start with all possible combinations
solutions = product(*slots)
# chain together ifilters to weed out the ones that fail any of the
# constraints. Note that for optimum performance, you should place the
# constraints in descending order of probability to fail
for constraint in constraints:
solutions = ifilter(constraint, solutions)
# We're going to do decorate, max, undecorate
solutions = ((value(solution), solution) for solution in solutions)
value, solution = max(solutions)
# get the indexes and return
return dict((name, slot.index(item)) for name, slot, item
in zip(slot_names, slots, solution))
Note that you should be storing the values as floats and not as strings! It's easier (because it's often automatic when you need it) to cast to string than a float. Then you can take the ugly casts out of my code. I was just to lazy to do it for you. Note that you can call with as many constraints as you want but only one set of attributes to maximize. This made sense to me. If you study the code and understand it, you should be able to modify it to suit your tastes.
Here's how I modified your data structure.
ITEMS = { 'helm': [{'Acid':' 2.71',
'Bludgeoning': '1.04',
'Cold': '2.71',
'Encumbrance': '8.00',
'Fire': '2.71',
'Holy': '2.71',
'Impact': '1.30',
'Lightning': '2.00',
'Name': 'Plate Helm',
'Piercing': '1.17',
'Slashing': '1.30',
'Unholy': '2.71'},
{'Acid': '2.18',
'Bludgeoning': '0.92',
'Cold': '2.18',
'Encumbrance': '7.00',
'Fire': '2.18',
'Holy': '2.18',
'Impact': '1.15',
'Lightning': '1.65',
'Name': 'Scale Helm',
'Piercing': '1.03',
'Slashing': '1.15',
'Unholy': '2.18'}],
'chest':[{'Acid': '5.47',
'Bludgeoning': '2.05',
'Cold': '5.47',
'Encumbrance': '32.00',
'Fire': '5.47',
'Holy': '5.47',
'Impact': '2.57',
'Lightning': '4.06',
'Name': 'Plate Chest',
'Piercing': '2.31',
'Slashing': '2.57',
'Unholy': '5.47'},
{'Acid': '4.45',
'Bludgeoning': '1.84',
'Cold': '4.45',
'Encumbrance': '28.00',
'Fire': '4.45',
'Holy': '4.45',
'Impact': '2.30',
'Lightning': '3.31',
'Name': 'Scale Cuirass',
'Piercing': '2.07',
'Slashing': '2.30',
'Unholy': '4.45'}]}
note that the values of the outermost dictionary are lists and not tuples as you said. There is a huge distinction!
Seems like a variation of the Knapsack problem. Dynamic programming should be good enough if your weight (stats?) limit is not too big.
Edit:
Here's a prototype in Java of the dynamic programming solution:
public static int getBestAcidSum(int[][] acid, int[][] fire, int maxFire) {
int slots = acid.length;
int[][] acidSum = new int[slots][maxFire + 1];
for (int j = 0; j < acid[0].length; j++)
acidSum[0][fire[0][j]] = Math.max(acidSum[0][fire[0][j]], acid[0][j]);
for (int i = 1; i < slots; i++)
for (int j = 0; j < acid[i].length; j++)
for (int fireSum = fire[i][j]; fireSum <= maxFire; fireSum++)
if (acidSum[i-1][fireSum - fire[i][j]] > 0)
acidSum[i][fireSum] = Math.max(acidSum[i][fireSum], acidSum[i-1][fireSum - fire[i][j]] + acid[i][j]);
int ret = 0;
for (int fireSum = 0; fireSum <= maxFire; fireSum++)
ret = Math.max(ret, acidSum[slots - 1][fireSum]);
return ret;
}
public static void main(String[] args) {
System.out.println(getBestAcidSum(new int[][] {{271, 218}, {547, 445}}, new int[][] {{271, 218}, {547, 445}}, 800));
}
The algorithm is O(N*C) where N is the total number of items and C is the constraint ("maxFire" in the example). Should work instantaneously with the quantities you've been mentioning.
The code is very simplified but it maintains the fundamental algorithmic difficulty. It only returns the optimal sum that fulfills the constraints. Should be easily modified to return the actual combination. Summing more than one stat together should be easily incorporated as well. Values were converted to integers by multiplying by 100.

C/C++/Java/C#: help parsing numbers

I've got a real problem (it's not homework, you can check my profile). I need to parse data whose formatting is not under my control.
The data look like this:
6,852:6,100,752
So there's first a number made of up to 9 digits, followed by a colon.
Then I know for sure that, after the colon:
there's at least one valid combination of numbers that add up to the number before the column
I know exactly how many numbers add up to the number before the colon (two in this case, but it can go as high as ten numbers)
In this case, 6852 is 6100 + 752.
My problem: I need to find these numbers (in this example, 6100 + 752).
It is unfortunate that in the data I'm forced to parse, the separator between the numbers (the comma) is also the separator used inside the number themselves (6100 is written as 6,100).
Once again: that unfortunate formatting is not under my control and, once again, this is not homework.
I need to solve this for up to 10 numbers that need to add up.
Here's an example with three numbers adding up to 6855:
6,855:360,6,175,320
I fear that there are cases where there would be two possible different solutions. HOWEVER if I get a solution that works "in most cases" it would be enough.
How do you typically solve such a problem in a C-style bracket language?
Well, I would start with the brute force approach and then apply some heuristics to prune the search space. Just split the list on the right by commas and iterate over all possible ways to group them into n terms (where n is the number of terms in the solution). You can use the following two rules to skip over invalid possibilities.
(1) You know that any group of 1 or 2 digits must begin a term.
(2) You know that no candidate term in your comma delimited list can be greater than the total on the left. (This also tells you the maximum number of digit groups that any candidate term can have.)
Recursive implementation (pseudo code):
int total; // The total read before the colon
// Takes the list of tokens as integers after the colon
// tokens is the set of tokens left to analyse,
// partialList is the partial list of numbers built so far
// sum is the sum of numbers in partialList
// Aggregate takes 2 ints XXX and YYY and returns XXX,YYY (= XXX*1000+YYY)
function getNumbers(tokens, sum, partialList) =
if isEmpty(tokens)
if sum = total return partialList
else return null // Got to the end with the wrong sum
var result1 = getNumbers(tokens[1:end], sum+token[0], Add(partialList, tokens[0]))
var result2 = getNumbers(tokens[2:end], sum+Aggregate(token[0], token[1]), Append(partialList, Aggregate(tokens[0], tokens[1])))
if result1 <> null return result1
if result2 <> null return result2
return null // No solution overall
You can do a lot better from different points of view, like tail recursion, pruning (you can have XXX,YYY only if YYY has 3 digits)... but this may work well enough for your app.
Divide-and-conquer would make for a nice improvement.
I think you should try all possible ways to parse the string and calculate the sum and return a list of those results that give the correct sum. This should be only one result in most cases unless you are very unlucky.
One thing to note that reduces the number of possibilities is that there is only an ambiguity if you have aa,bbb and bbb is exactly 3 digits. If you have aa,bb there is only one way to parse it.
Reading in C++:
std::pair<int,std::vector<int> > read_numbers(std::istream& is)
{
std::pair<int,std::vector<int> > result;
if(!is >> result.first) throw "foo!"
for(;;) {
int i;
if(!is >> i)
if(is.eof()) return result;
else throw "bar!";
result.second.push_back(i);
char ch;
if(is >> ch)
if(ch != ',') throw "foobar!";
is >> std::ws;
}
}
void f()
{
std::istringstream iss("6,852:6,100,752");
std::pair<int,std::vector<int> > foo = read_numbers(iss);
std::vector<int> result = get_winning_combination( foo.first
, foo.second.begin()
, foo.second.end() );
for( std::vector<int>::const_iterator i=result.begin(); i!=result.end(), ++i)
std::cout << *i << " ";
}
The actual cracking of the numbers is left as an exercise to the reader. :)
I think your main problem is deciding how to actually parse the numbers. The rest is just rote work with strings->numbers and iteration over combinations.
For instance, in the examples you gave, you could heuristically decide that a single-digit number followed by a three-digit number is, in fact, a four-digit number. Does a heuristic such as this hold true over a larger dataset? If not, you're also likely to have to iterate over the possible input parsing combinations, which means the naive solution is going to have a big polynomic complexity (O(nx), where x is >4).
Actually checking for which numbers add up is easy to do using a recursive search.
List<int> GetSummands(int total, int numberOfElements, IEnumerable<int> values)
{
if (numberOfElements == 0)
{
if (total == 0)
return new List<int>(); // Empty list.
else
return null; // Indicate no solution.
}
else if (total < 0)
{
return null; // Indicate no solution.
}
else
{
for (int i = 0; i < values.Count; ++i)
{
List<int> summands = GetSummands(
total - values[i], numberOfElements - 1, values.Skip(i + 1));
if (summands != null)
{
// Found solution.
summands.Add(values[i]);
return summands;
}
}
}
}

Dynamic programming problems

I'm looking for some pointers about a dynamic programming problem. I cannot find any relevant information about how to solve this kind of problem. The only kind of problem I know how to solve using dynamic programming is when I have two sequences and create a matrix of those sequences. But I don't see how I can apply that to the following problem...
If I have a set A = {7,11,33,71,111} and a number B. Then C which is a subset of A, contains the elements from A which builds the sum B.
EXAMPLE:
A = {7,11,33,71,111}
If B = 18, then C = {7,11} (because 7+11 = 18)
If B = 3, then there is no solution
Thankful for any help here, I just don't know how to think when solving these kind of problems. I cannot find any general method either, only some examples on gene sequences and stuff like that.
Dynamic programming is a broad category of solutions wherein a partial solution is kept in some structure for the next iteration to build upon instead of having it recalculate the intermediate results over and over again.
If I were to take a dynamic approach to this particular problem, I would probably keep a running list of every sum calculable from the previous step, as well as the set used to compute that sum.
So for example the first iteration my working set would contain {null, 7}, then I would add 11 to everything in that that set as well as the set itself (let's pretend that null+11=11 for now). Now my working set would contain {null, 7, 11, 18}. For each value in the set, I would keep track of how I got that result: so 7 maps to the original set {7} and 18 maps to the original set {7,11}. Iteration would end when either A) the target value is generated or B) the original set is exhausted without finding the value. You could optimize the negative case with an ordered set, but I'll leave figuring that out to you.
There is more than one way to approach this problem. This is a dynamic solution, and it's not very efficient as it needs to build a set of 2^(size of set) members. But the general approach corresponds to what dynamic programming was created to solve.
I think dynamic approach depend on B and number elements of A.
I suggested a dynamic approach in this case with B*number element of A <= 1.000.000
Use call F[i,j] is true if use can use from A[1] to A[j] to build i and false otherwise
So each step you have to choise:
use a[j] then F[i,j]=F[i-a[j],j-1]
don't user a[j] then F[i,j] = F[i,j-1]
Then if existing a F[B,*]=1 ,you can build B.
Bellow is example code:
#include<stdio.h>
#include<iostream>
using namespace std;
int f[1000][1000], a[1000], B,n;
// f[i][j] = 1 => can build i when using A[1]..a[j], 0 otherwisw
int tmax(int a, int b){
if (a>b) return a;
return b;
}
void DP(){
f[0][0] = 1;
for (int i=1;i<=B;i++)
for (int j=1;j<=n;j++)
{
f[i][j] = f[i][j-1];
if (a[j]<=i)
f[i][j] = tmax(f[i-a[j]][j-1], f[i][j]);
}
}
int main(){
cin >> n >> B;
for (int i=1;i<=n;i++) cin >>a[i];
DP();
bool ok = false;
for (int i=1;i<=n;i++){
if (f[B][i]==1) {
cout<<"YES";
ok = true;
break;
}
}
if (!ok) cout <<"NO";
}

Resources