After participating in Google Code Jam 2012 Round 2, it occurred to me that the Mountain View problem boiled down to solving a set of linear inequalities, which could be done in Mathematica. I've only tinkered with Mathematica programming before, but I tried it out to see how hard it was for this problem. I got it to work (for the "small" input set only) with a lot of effort. I felt like I must be doing some things the hard way and would like feedback on the proper Mathematica idioms for file I/O and expression building (and anything else).
You may have to read the problem description (link above), but the basics are:
- You read test cases from an input file, C.in.
- You write answers to an output file, C.out.
- Each input case contains a number of mountains and a constraint number for each mountain.
- Each output line contains a list of possible mountain heights or the word "Impossible"
My program follows.
During development, I send output to stdout. debug toggles that. I put it early because I thought I might use it for Print statements.
debug = False;
This function solves a single case, including reading input and writing output.
solveCase[in_, out_, cn_] :=
Module[{nm, im, highest, vars, constraints, i, j, k, rhs, lhs, yk,
yi, yj, answer},
Read the input: the number of mountains and the apparent highest mountain that can be seen from each of the first nm-1 mountains.
nm = Read[in, Number];
highest = Array[0, nm - 1];
For[im = 1, im <= nm - 1, im++,
highest[[im]] = Read[in, Number];
];
Start setting up expressions to pass later to FindInstance. Is there a way to solve for a vector of variables without giving each one a separate name? Not finding any, I create the variables as h1, h2, ... and the initial constraints as h1 >= 0, h2 >= 0, ...
vars =
Function[x, ToExpression["h" <> ToString[x]]] /@ Range[nm];
constraints =
Function[x, ToExpression["h" <> ToString[x]] >= 0] /@ Range[nm];
Convert the highest info into a list of constraints. When mountain i sees mountain k as the highest, it means the slope of the line between their peaks is above the line for each j between i and k and above or at the line for each j after k.
For[i = 1, i <= nm - 1, i++,
k = highest[[i]];
For[j = i + 1, j <= nm, j++,
If[j == k, Continue[]];
Build constraint, (hk - hi) * (j - i) GT/GE (hj - hi) * (k - i). This part seems especially clumsy. I ended up resorting to strings, but there must be a way to do it at the expression level.
yk = "h" <> ToString[k];
yi = "h" <> ToString[i];
yj = "h" <> ToString[j];
lhs = ToExpression["(" <> yk <> " - " <> yi <> ") * " <> ToString[j - i]];
rhs = ToExpression["(" <> yj <> " - " <> yi <> ") * " <> ToString[k - i]];
If[i < j, AppendTo[constraints, Greater[lhs, rhs]],
AppendTo[constraints, GreaterEqual[lhs, rhs]]];
];
];
The real work:
answer = FindInstance[constraints, vars, Integers];
Write the output as Case #N: h1 h2 ....
WriteString[out, "Case #", cn, ": "];
If[Length[answer] > 0,
answer = answer[[1]][[ All, 2]];
For[i = 1, i <= nm , i++, WriteString[out, answer[[i]]];
If[i < nm, WriteString[out, " "], WriteString[out, "\n"]]],
WriteString[out, "Impossible\n"]];
;
];
The "main" program. Set up in and out and cycle through the cases. I'm guessing the entire program should go in a Module with local-only variables.
in = OpenRead["~/Documents/math/C.in"];
If[debug, out = OutputStream["stdout", 1],
out = OpenWrite["~/Documents/math/C.out"]];
ncases = Read[in, Number];
For[ic = 1, ic <= ncases, ic++, solveCase[in, out, ic]];
Close[in];
If[! debug, Close[out]];
This method takes forever for the 1000+ mountain case, so if there is a better way than FindInstance, I'd like to hear about that, too. Or maybe the code needs to take into account higher level constraints rather than solving the most general form of the problem.
Note: After seeing no use of Mathematica (Code Jam Language Stats) in previous contests, I realized Mathematica is not allowed because there is no free version, so this is even more of an academic exercise than I intended.

ToExpression[string]. BTW, Matlab is allowed because Octave is a free clone. – xan Jun 04 '12 at 13:12Integrate, it is practically impossible to create a true replacement which will actually be able to run most Mathematica programs. – Szabolcs Jun 04 '12 at 14:19