One Point Solution

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Saturday, 10 August 2013

Test SRM#2 : In which I abuse lambdas

Posted on 16:31 by Unknown

So, today we had a new test SRM in TopCoder. This time testing the g++ 4.8.1 compiler and a python upgrade too. g++ 4.8.1 has some amazing features over 4.4. So I really wanted to use them in this test. (Disclaimer: I am actually just learning c++11)

Div1 hard

It was a dynamic programming problem. I solved this one before, and though I avoided looking at the past solution, the idea was still evident. This problem is such a standard dynamic programming problem that I don't think we would be able to use it in division 1 as a medium anymore. It was a division 1 hard back in its day...

Was sad because I couldn't find an excuse to put any of the new features.

Div1 Medium: FlightScheduler

The maximum distance a plane can travel given an initial mass of fuel `f` is: `R = K ln( (m + f - t) / m )` where:

  • `K` is a constant for the plane (efficiency)
  • `m` is the plane's mass.
  • `t` is the mass of fuel spent during take off, so the initial amount of fuel has to be at least this.

(Special effort was put to make the problem statement as unclear as possible. I initially didn't know that the take off amount wasn't included in the first formula that appears in the problem statement. This really delayed me).

Anyway, so knowing that, we need to minimize the amount of fuel needed to travel `D` distance units. We are allowed to land at any intermediary point, recharge fuel and take off.

Equal distances

The first thing to know is that if we make `(n-1)` stops, so that the plane takes off `n` times in total, it is always better to cover the same distance in each of the sub-trips. So we should move `D / n` units in each of them.

The independent variable that determines the final fuel cost is then just `n`. We need to find the best value of `n` for this.

Ternary search

So, let us say we make one flight. In this case, the amount of fuel needed for a single round might be too large (Note that the formula for R is logarithmic in the mass of fuel, so increasing the amount of fuel by a large amount will not increase the distance that much).

If we instead do a lot of flights, it is also not very good, because each flight needs at least `t` fuel.

There is a value of `n` that will yield a minimum value for `f(n)`, the total fuel cost. For `(x < n)` and `(y > n)`, we can guess that: `(f(x) > n)` and (f(y) > n). Also, the more we move away from `n`, the worse the result. This is all ternary search-friendly. Let us do it.

f(n)

So let us just find `f(n)`, the minimum fuel cost needed to travel `D` distance units using `n` trips. Let `(d = D / n)` , this is the distance per trip. What is the minimum fuel cost to travel `d` distance units? We need the following to be true::

`K ln( (m + f - t) / m ) >= d`

Let us solve the inequality.

`ln( (m + f - t) / m ) >= d / K`
`(m + f - t) / m >= e ^(d / K)`
`m + f - t >= me ^(d / K)`
`f >= me ^(d / K) - m + t`
`f >= m(e ^(d / K) - 1) + t`

So that is the lower bound for f.

Implementing ternary search

So, I really wanted to use the new c++ features. You know what is funny about ternary search? You need to implement the function f. You know what is lame about solving TC problems using multiple functions? TURNING ARGUMENTS INTO CLASS MEMBERS. It is so tedious to copy variables manually just so a new function can use them in their scope. OOP is truly the worst idea ever. Anyway. It occurred to me... I can use a closure! This way when I create the function f() I will do it inside the scope of the main method, so no need to copy arguments manually.

The result is beautiful:


double minimizeFuel(int distance, int K, int emptyMass, int takeoffFuel)
{
// so we use closure syntax. The [=] means
// that any variable like "emptyMass"
// that is referenced inside the anonymous function (lambda) will be
// automatically copied, so when we call f() it will use copies just fine.

auto f = [=](long n)->double {
double d = distance * (1.0 / n);
return n * ( takeoffFuel + emptyMass * (exp(d/K) - 1.0) );
};

long lo = 1, hi = 40000100000L;
while (lo + 2 < hi) {
long ha1 = (lo*2 + hi) / 3, ha2 = (lo + hi*2) / 3;
if ( f(ha1) < f(ha2) ) {
hi = ha2;
} else {
lo = ha1;
}
}
// the minimum is one of f(lo), f(lo+1) or hi = f(lo+2):
vector<double> res = { f(lo), f(lo+1), f(lo+2) };
return *min_element(res.begin(), res.end());
}

It turns out that I had to go out in the middle of the match , so I didn't have much time to finish this problem correctly. When I came back, there were few minutes left of coding phase. I tried to debug, I found the bug (The issue with problem statement I mentioned above). But it was still wrong. Eventually, when there were only 5 minutes left, I gave up trying to find the bug and moved on to 250. It turns out that my bug was that I did: d = distance / n. Both distance and n were integers, so it was doing integer division....

Div1 Easy

An implementation problem, I didn't have much time to finish it.

And more

It turns out that lambdas and closures are awesome. There is plenty of more in regards to this new functional c++.

After the match, I figured, that I could actually make myself a TernarySearch library (template) function that does the whole TernarySearch for me and can be used in any situation.


// D: function domain
// R: function range , so f: D -> R
// Yep, std::function is useful:
template<class D, class R> R TernarySearch(D lo, D hi, std::function<R(D)> f) {
while (lo + 2 < hi) {
D ha1 = (lo*2 + hi) / 3, ha2 = (lo + hi*2) / 3;
if ( f(ha1) < f(ha2) ) {
hi = ha2;
} else {
lo = ha1;
}
}
vector<R> res = { f(lo), f(lo+1), f(lo+2) };
return *min_element(res.begin(), res.end());
}

So, if I wanted to use this function to solve today's problem:


double minimizeFuel(int distance, int K, int emptyMass, int takeoffFuel)
{
return TernarySearch<long, double>(1, 40000100000L, [=](long n){
double d = distance * (1.0 / n);
return n * ( takeoffFuel + emptyMass * (exp(d/K) - 1.0) );
});
}

Or maybe you prefer the following version:


double minimizeFuel(int D, int K, int m, int t)
{
std::function<double(long)> f = [=](long n){
return n*( t + m * (exp(D / (1.0*n*K)) - 1) );
};
return TernarySearch(1L, 40000100000L, f);
}

Comments?

What do you think of g++ 4.8.1 so far? Worthwhile upgrade?

Email ThisBlogThis!Share to XShare to Facebook
Posted in c++, implementation, srm, ternarysearch, topcoder | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • TopCoder SRM 557 - finally
    SRM 557 Explanation for division 1 Easy and match recap. Explanations for div2 easy and div2 medium. It feels like it has been ages since t...
  • SRM 589 Editorial
    I have finished writing the editorial for TopCoder SRM 589: http://apps.topcoder.com/wiki/display/tc/SRM+589 . As you most likely noticed. L...
  • SRM 590 recap and editorial
    Another week another Topcoder match. Not a great day. I had a bad flu and still do. Div1 500: The one with Xor Given a list of cards with nu...
  • SRM 546: relief
    I figured I should post something about this SRM. I've been very busy these weeks because the semester is ending and I tried to win a t-...
  • SRM 526: The killing wait for results
    While I wait for results, here is my perspective on this algorithm contest. It began with issues, it had to be postponed 15 minutes. TC has ...
  • SRM 554 div1 hard: TheBrickTowerHardDivOne
    Link to problem statement We got infinitely many bricks of dimensions 1x1x1 and C different colors. Count the number of towers of size 2x2...
  • SRM 533: Div1 500 MagicBoard explanation
    Finally solved it. It is a nice problem that is worth explaining in a post. You have a grid/board of at most 50x50 cells. Some cells contain...
  • Member SRM 505: Part 1
    So, let me explain a couple of problems from a Topcoder Member SRM that I wrote and never got an editorial. BTW, it was the last member SRM....
  • ListedLinks 2012-02-10
    Saturday Morning Breakfast Cereal comics: Grace Hopper's ghost That Oracle engineer blog post Oracle would really not like anyone to se...
  • Codeforces "Good bye 2013" round
    So it was a special round for coders of both divisions, problems ranged from the super easy problem A to the super difficult problems E,F,G....

Categories

  • acm
  • algorithm
  • answers
  • arenaplugin
  • badday
  • behindthescenes
  • bugs
  • c++
  • censorship
  • codechef
  • codeforces
  • contests
  • crocchamp
  • editorial
  • editorial.srm
  • embarrassing
  • explanation
  • gcj2013
  • gmp
  • goodday
  • google
  • googlecodejam
  • greed
  • groklaw
  • health
  • html
  • httpseverywhere
  • implementation
  • ipsc
  • ispc
  • java
  • kawigiedit
  • kindagoodday
  • lamebook
  • languages
  • lego
  • listedlinks
  • marathon
  • nasa
  • offtopic
  • ouch
  • postmortem
  • postportem
  • practical
  • probably_not_a_good_tip
  • problemsetting
  • programming
  • python
  • quora
  • rant
  • recap
  • slightlygoodday
  • snippet
  • srm
  • stl
  • strategy
  • swerc
  • tco
  • tco12
  • tco13
  • tco2012
  • tco2013
  • ternarysearch
  • topcoder
  • tricks
  • ubuntu
  • uva
  • vjass
  • vkcup
  • wc3
  • zinc

Blog Archive

  • ►  2014 (1)
    • ►  January (1)
  • ▼  2013 (141)
    • ►  December (14)
    • ►  November (8)
    • ►  October (13)
    • ►  September (11)
    • ▼  August (14)
      • Regarding c++ vs. python (in algorithm contests)
      • SRM 589 Editorial
      • SRM 589: Read the statement! (upd)
      • Codeforces #196: slowness
      • SRM 588: ouch (Update)
      • Editorial for SRM 587 is out
      • Test SRM#2 : In which I abuse lambdas
      • ThreeColorabilityEasy (SRM 587 div2 hard)
      • ThreeColorability (SRM 587 div1 hard)
      • SRM 587 editorial previews
      • Test SRM #2 : Revenge of the C++11
      • KawigiEdit 2.3.0
      • SRM 586 Editorial finally there
      • SRM 586 div1 easy and hard editorials
    • ►  July (15)
    • ►  June (13)
    • ►  May (13)
    • ►  April (12)
    • ►  March (11)
    • ►  February (11)
    • ►  January (6)
  • ►  2012 (94)
    • ►  December (5)
    • ►  October (6)
    • ►  September (8)
    • ►  August (6)
    • ►  July (3)
    • ►  June (5)
    • ►  May (8)
    • ►  April (10)
    • ►  March (20)
    • ►  February (16)
    • ►  January (7)
  • ►  2011 (51)
    • ►  December (7)
    • ►  November (12)
    • ►  October (5)
    • ►  September (1)
    • ►  August (3)
    • ►  July (4)
    • ►  June (3)
    • ►  May (7)
    • ►  April (3)
    • ►  March (2)
    • ►  February (1)
    • ►  January (3)
  • ►  2010 (9)
    • ►  December (4)
    • ►  October (1)
    • ►  June (1)
    • ►  May (1)
    • ►  January (2)
  • ►  2009 (1)
    • ►  December (1)
Powered by Blogger.

About Me

Unknown
View my complete profile