i finally found a solution, but not the book solution. I wonder why these optimization functions don't check all the boundary values. that is to say, why not check {alb,c,d}={1,0,0,0} and {0,1,0,0} and {0,0,1,0} and {0,0,0,1} and {1,1,0,0} etc. etc.
In[6]:= projCosts = {{40, 10, 20, 20, 0}, {65, 36, 30, 25, 30}, {6, 8,
10, 0, 0}, {20, 10, 20, 20, 0}}; yearlyFunds = {120, 40, 40, 55,
60}; totalPossibleFunds = {90, 65 + 36 + 30 + 25 + 30, 6 + 8 + 10,
20 + 10 + 20 + 20};
In[7]:= projScore = {.741, .845, .353, .457};
In[17]:= NMaximize[{projScore . {a, b, c,
d}, ({projCosts[[1]][[1]], projCosts[[2]][[1]],
projCosts[[3]][[1]], projCosts[[4]][[1]]} . {a, b, c, d}) <=
yearlyFunds[[
1]] && ({projCosts[[1]][[2]], projCosts[[2]][[2]],
projCosts[[3]][[2]], projCosts[[4]][[2]]} . {a, b, c, d}) <=
yearlyFunds[[
2]] && ({projCosts[[1]][[3]], projCosts[[2]][[3]],
projCosts[[3]][[3]], projCosts[[4]][[3]]} . {a, b, c, d}) <=
yearlyFunds[[
3]] && ({projCosts[[1]][[4]], projCosts[[2]][[4]],
projCosts[[3]][[4]], projCosts[[4]][[4]]} . {a, b, c, d}) <=
yearlyFunds[[
4]] && ((totalPossibleFunds[[1]]*a +
totalPossibleFunds[[3]]*c)/(totalPossibleFunds[[1]]*a +
totalPossibleFunds[[3]]*c + totalPossibleFunds[[2]]*b +
totalPossibleFunds[[4]]*d)) <= 0.4 && 0 <= {a, b, c, d} <= 1 &&
a + b + c + d > 0 && Element[{a, b, c, d}, Integers]}, {a, b, c,
d}, Method -> {"NelderMead"}]
Out[17]= {0.81, {a -> 0, b -> 0, c -> 1, d -> 1}}
(*this isn't the solution provided in the book solution set, but the \
cost of my solution is half that of the book's solution*)