The Glade 4.0 https://gladerebooted.net/ |
|
Cool programming problem https://gladerebooted.net/viewtopic.php?f=5&t=5384 |
Page 1 of 1 |
Author: | Lex Luthor [ Tue Feb 01, 2011 9:58 am ] |
Post subject: | Cool programming problem |
My friend sent this to me last night. Quote: I'm just trying to practice programming but that one is pissing me off. It's like I end up with infinitely many nested for loops and I can't quite figure out the recursion For the final task, you must find all subsets of an array where the largest number is the sum of the remaining numbers. For example, for an input of: (1, 2, 3, 4, 6) the subsets would be 1 + 2 = 3 1 + 3 = 4 2 + 4 = 6 1 + 2 + 3 = 6 Here is the list of numbers you should run your code on. The password is the number of subsets. In the above case the answer would be 4. This is my solution: Spoiler: |
Author: | Stathol [ Wed Feb 02, 2011 8:44 pm ] |
Post subject: | |
I banged something out pretty quickly, and then discovered that I had come up with the same solution you had. So then I started thinking about optimization. That turned out to be a lot more interesting than just finding some appropriate loop structures to deal with the combinatorics. Eventually I wound up scrapping the iterative approach and went with a recursive design. I think I've optimized it about as much as can be, short of converting it to an equivalent iterative design. That would be a lot of headache for not much benefit, though. As is, the algo itself is about 6500-7000x faster than the brute-force iterative method. This is probably ugly Python code, but I only started teaching it to myself a couple weeks ago, so...eh. Spoiler: Now I'm wondering if there's an even faster solution that involves working backwards from the possible final sums. I bet there is. |
Author: | Lex Luthor [ Wed Feb 02, 2011 9:27 pm ] |
Post subject: | |
Wow, your solution is really fast! I'm trying to think of a fast way without doing recursion. |
Author: | Stathol [ Wed Feb 02, 2011 11:40 pm ] |
Post subject: | |
Haha, I just discovered that my algo is pretty sensitive to skewed input sets. Changing the final number in the input set from 99 to 1000 makes the total script execution time jump from ~0.025s to ~4.9s, it's not so much that it doesn't cope with large input values, but rather it really doesn't like it when there's a big gap in the numbers. Further changing the 97 to 999 brings the execution time down to ~2.9s, for instance. The brute-force approach doesn't care about the distribution of values, it's only affected by the number of inputs. Each one roughly doubles the execution time, as you might expect. In that respect, my algo scales better. But it just goes to show that benchmarking is never quite as clear as it seems. I may convert my algo to an iterative function with a state stack just to see how much it improves. The really nasty challenge is whether there's a constant-space iterative solution. I'm guessing not. This seems to be a close relative of the subset sum problem and the infamous knapsack problem. I'm curious where your friend encountered this, and if it's a well-known computing problem that I'm just not familiar with. |
Author: | Noggel [ Thu Feb 03, 2011 2:45 am ] |
Post subject: | Re: Cool programming problem |
Man. I just got three problems in this same vein from a CS professor for this Olympiad thing he is running. I like them in theory but I think I quickly wound up out of my league here in this thread. :p I keep finding ways to convert the problem at hand into something brute forceable through sheer iteration. Effective, and even pretty practical given the speed of computers, but elegant it is not. It's way too late for me to be awake now but I just finished the third problem and it is... laughable. Oh I got a working solution, eventually, but it's kinda Rube Goldbergian. My other two aren't too bad as far as interative designs go, but this third one... yeah. I think I'll paste it here tomorrow for everyone to mock. :p The code is all in basic C++, but the spirit of all these problems is more or less math anyway, so the language is pretty irrelevant. Because of its Goldbergian nature, I'll probably have to comment it to even make it readable, though, so it should be plenty readable no matter your knowledge of C++. The only good to come of it was it got me thinking about things in rather unusual ways. When you end up having to develop a loop to increment in some kind of base 3, without including 0 (111 -> 112 -> 113 -> 121), you know your code went way off track somewhere a step or three back. :p I'd actually be a little proud of my solution to accomplish that if it wasn't my only way out of such a ridiculous situation to begin with! All in good fun I suppose... :p |
Author: | Noggel [ Thu Feb 03, 2011 3:38 pm ] |
Post subject: | Re: Cool programming problem |
So many lines of code! Problem is problem 3 from this .pdf: Computer Science Olympiad I may have to fiddle around with the code to get exactly the desired output (think it only wants one result, for example, and some sort of 'no solutions' output needs to be added too) but the gist of the program seems complete. Spoiler: I cringe a little at the flag char use. It was a temporary solution when I was in the middle of some other problem that worked without problems, so it stuck around. I'll probably add input validation too before turning in any code, but I'll check with the professor running this if that's necessary or not. I get the impression I reinvented the wheel a few times here, but alas. Working with ints are a pain in C++. Data type conversions seem like they should be so easy, but it is not so. I did want to stick to a pretty math-centric algorithm anyway as opposed to picking it apart as a string. |
Author: | Stathol [ Fri Feb 04, 2011 12:19 am ] |
Post subject: | |
I threw together a program for this. It's purely brute force, but I don't think that's much of an issue, because the keyspace is so small. If a, b, and c are all different, we can construct 27 (3^3) unique 3-digit numbers from them which are candidates for p, q, and r. Then from these we can choose any 3, with repetition, but order does not matter. That is, p + q + r = r + q + p, etc. So the maximum number of "unique" p + q + r equations that can be built is: C(27 + 3 - 1, 3) = C(29,3) = 3654 If exactly two out a, b, c are equal to one another, then there are 2^3 = 8 candidates and therefore the unique p, q, r equations are reduced to: C(8 + 3 - 1, 3) = C(10,3) = 120 And obviously if a = b = c, there is only one possible unique equation p + q + r that can be built. My program operates according to the process outline above. First it builds the list of candidates for p, q, and r. Afterwards, it iterates over the unique combinations of p, q, and r, checking for sums. I'm sure this could be made more efficient by various means. Offhand, you could certainly exploit parity rules. Divide the candidates into evens and odds. If N is odd, you can test only those combinations containing one odd and two evens, or three odds, etc. However, given that there are most <4k keys to test, the value of such optimizations seems dubious. My first crack at this was in Python: http://meriwoker.dyndns.org/~stathol/glade/3by3.py But morbid curiosity got the better of me, so I ported it to C++: http://meriwoker.dyndns.org/~stathol/glade/3by3.cpp I included the ability in both progs to loop the algo 10k times with random inputs for profiling purposes: Python: Code: <redacted>@juliet:~# /usr/bin/time ./3by3.py --profile > /dev/null 8.06user 0.01system 0:08.07elapsed 100%CPU (0avgtext+0avgdata 20368maxresident)k 0inputs+0outputs (0major+1388minor)pagefaults 0swaps C++: Code: <redacted>@juliet:~# /usr/bin/time ./3by3-profile > /dev/null 0.07user 0.01system 0:00.08elapsed 102%CPU (0avgtext+0avgdata 4112maxresident)k 0inputs+0outputs (0major+293minor)pagefaults 0swaps *sigh* It's okay, Python. I still love you. :/ |
Author: | Noggel [ Mon Feb 07, 2011 5:07 am ] |
Post subject: | Re: Cool programming problem |
Always cool to see different ways to tackle the same problem! Especially when it goes far beyond my CMPSC 101 learnings. Ah well. I suppose I only regret not figuring out some way to limit the algorithm from searching for A + C + B when it has already done A + B + C, and so on. Perhaps if I'm extra ambitious I'll try and add that in. |
Author: | Taskiss [ Wed Feb 09, 2011 10:20 pm ] |
Post subject: | Re: Cool programming problem |
Behold the power of the camel...I just love perl! if it could do binary natively it would have been much faster...and I calculated the series where, when the largest number was the sum of the series, I displayed it. I'm not sure if that's the goal, but it made for an interesting problem so I ran with it. Note: Ah, I see what you want... Code: #!/usr/bin/perl -w use strict ; my @array = qw(3 4 9 14 15 19 28 37 47 50 54 56 59 61 70 73 78 81 92 95 97 99) ; my ($result, $mask, $loop, $maskLen) ; while (scalar(@array) > 2) { $result = pop (@array) ; $mask = "1" x scalar(@array) ; $loop = &mask2d($mask) ; $maskLen = length($mask) ; &doit ; } exit ; #------------------------------------------------------------------------------- sub doit { for (my $i = 0; $i <= $loop; $i++) { my @bits = split(//, &d2mask($i)) ; my @list = () ; my $sum = 0 ; LOOP: { for (my $i = 0; $i < $maskLen ; $i++) { if ($bits[$i] eq 1) { push (@list, $array[$i]) ; $sum += $array[$i] ; if ($sum > $result) { last LOOP } } } } if ($sum == $result) { print "The series \(@list\) = $result\n" } } } #------------------------------------------------------------------------------- sub d2mask { my $str = unpack("B32", pack("N", shift)) ; $str =~ s/^0+(?=\d)// ; $str = sprintf("%${maskLen}s", $str) ; $str =~ tr/ /0/ ; return ($str) ; } #------------------------------------------------------------------------------- sub mask2d { return unpack("N", pack("B32", substr("0" x 32 . shift, -32))) ; } #------------------------------------------------------------------------------- results: Spoiler: OK, ver 1.2... went from 2m14 to 0m50 Code: #!/usr/bin/perl -w
my @array = qw(3 4 9 14 15 19 28 37 47 50 54 56 59 61 70 73 78 81 92 95 97 99) ; #my @array = qw(1 2 3 4 6) ; my $result = pop(@array) ; my $target = pop(@array) ; my @solution ; print "Calculating...\n" ; while (scalar(@array) > 0) { my $mask = "1" x scalar(@array) ; my $maskLength = length($mask) ; my $loop = unpack("N", pack("B32", substr("0" x 32 . $mask, -32))) ; my $i = 0 ; while ($i <= $loop) { my @bits = split(//, substr(unpack("B*", pack("N", $i)), -$maskLength, $maskLength)) ; my @list = () ; my $sum = 0 ; my $x = 0 ; foreach my $bit (@bits) { if ($bit) { $sum += $array[$x] ; last if ($sum > $result) ; push (@list, $array[$x]) ; } $x++ ; } push (@solution, "\(@list\) = $result\n") if ($sum == $result ) ; push (@solution, "\(@list $target\) = $result\n") if ($sum + $target == $result ) ; $i++ ; } $result = $target ; $target = pop(@array) ; } foreach (reverse @solution) { print } |
Page 1 of 1 | All times are UTC - 6 hours [ DST ] |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |