<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress/2.3.1" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>
<channel>
	<title>Comments on: Possible Test Scores</title>
	<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/</link>
	<description>Loren Shure  works on design of the MATLAB language at &#60;a href="http://www.mathworks.com/"&#62;The MathWorks&#60;/a&#62;. She writes here about once a week on MATLAB programming and related topics. &#60;br&#62;&#60;br&#62;&#60;a href="/images/loren-full.jpg"&#62;&#60;img src="/images/loren.jpg"&#62;&#60;/a&#62;</description>
	<pubDate>Sun, 22 Nov 2009 23:18:57 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.1</generator>
		<item>
		<title>By: Ben</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29925</link>
		<dc:creator>Ben</dc:creator>
		<pubDate>Thu, 11 Dec 2008 22:33:34 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29925</guid>
		<description>Interesting problem.
 
Tom, you could also try q(q&#62;0)=1 instead of the /5 step (avoids having q(1) go to zero).

Here's a one-liner solution that works ok for small problems:
 
&#62;&#62; find(round(ifft(fft([full(sparse(1,Points+1,1,1,max(Points)+1)),zeros(1,max(Points)*(N-1))]).^N))==0)-1
 
ans =
 
     1     2     4     7    49    52    54    55</description>
		<content:encoded><![CDATA[<p>Interesting problem.</p>
<p>Tom, you could also try q(q&gt;0)=1 instead of the /5 step (avoids having q(1) go to zero).</p>
<p>Here&#8217;s a one-liner solution that works ok for small problems:</p>
<p>&gt;&gt; find(round(ifft(fft([full(sparse(1,Points+1,1,1,max(Points)+1)),zeros(1,max(Points)*(N-1))]).^N))==0)-1</p>
<p>ans =</p>
<p>     1     2     4     7    49    52    54    55</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: matt fig</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29924</link>
		<dc:creator>matt fig</dc:creator>
		<pubDate>Tue, 09 Dec 2008 19:21:30 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29924</guid>
		<description>Ilya Rozenfeld,

Your solution will fail for N&#62;=10 because of this:

dec2base(10,11,4)

ans =
 
000A


We would like 000(10) but of course that is not possible.</description>
		<content:encoded><![CDATA[<p>Ilya Rozenfeld,</p>
<p>Your solution will fail for N&gt;=10 because of this:</p>
<p>dec2base(10,11,4)</p>
<p>ans =</p>
<p>000A</p>
<p>We would like 000(10) but of course that is not possible.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: matt fig</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29923</link>
		<dc:creator>matt fig</dc:creator>
		<pubDate>Tue, 09 Dec 2008 16:39:22 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29923</guid>
		<description>A couple of observations got me to thinking about this question in general.  One is that for a certain number of questions N , usually less than 6, some Points vectors return an impossible-scores vector which is the same   
length (L) for any M &#62; N. The second observation is that, once this N is found, the last (L - k) elements in the impossible-scores vector are multiples of the largest value in Points added to those same (L - k) values given for N.  Thus once this N is found, the problem reduces to a simple multiplication and addition.  This led me to add to Lucio's first solution specifically for large N.  These additions don't seem to add too much time when there is no savings to be had (e.g. Points = [0 2], or small number of questions), but when it does work there can be a tremendous gain in speed, for M &#62; N.

    
for example:  

Points = [0 3 5 8];

tic, lucios(10000,Points),toc

tic,matts(10000,Points),toc

Even for N = 100, the augmented solution is 20 times faster on my machine.
Anyway, interesting problem!


&lt;pre&gt; &lt;code&gt;

function nonScores4 = matts(N,Points)
% Assumes Points is sorted and has only unique values.  This is an
% extention of Lucio's solution.

a = false(max(Points),1);
a(nonzeros(Points)) = true;
t1 = [1 NaN];% These two are used in the augmented code below.
cnt = 1;%

for i = 1:N-1
    a(bsxfun(@plus,find(a),Points)) = true;
    t2 = t1;  %  Start augmented code.
    t1 = find(~a)'; % t1,t2 Successive vectors for successive #'s of q's.
    if ~isempty(t1) &#38;&#38; ~isempty(t2) &#38;&#38; numel(t1)==numel(t2) &#38;&#38; t2(end)==(t1(end)-Points(end)) 
        cnt = cnt + 1;
        if cnt == 3
            vct = t1~=t2;
            t2(vct) = t2(vct) + (N-i)* Points(end);
            nonScores4 = t2;  
            return % We can skip the rest of the iterations.
        end
    end  % End augmented code.
end

nonScores4 = find(~a)';

&lt;/code&gt; &lt;/pre&gt;</description>
		<content:encoded><![CDATA[<p>A couple of observations got me to thinking about this question in general.  One is that for a certain number of questions N , usually less than 6, some Points vectors return an impossible-scores vector which is the same<br />
length (L) for any M &gt; N. The second observation is that, once this N is found, the last (L - k) elements in the impossible-scores vector are multiples of the largest value in Points added to those same (L - k) values given for N.  Thus once this N is found, the problem reduces to a simple multiplication and addition.  This led me to add to Lucio&#8217;s first solution specifically for large N.  These additions don&#8217;t seem to add too much time when there is no savings to be had (e.g. Points = [0 2], or small number of questions), but when it does work there can be a tremendous gain in speed, for M &gt; N.</p>
<p>for example:  </p>
<p>Points = [0 3 5 8];</p>
<p>tic, lucios(10000,Points),toc</p>
<p>tic,matts(10000,Points),toc</p>
<p>Even for N = 100, the augmented solution is 20 times faster on my machine.<br />
Anyway, interesting problem!</p>
<pre> <code>

function nonScores4 = matts(N,Points)
% Assumes Points is sorted and has only unique values.  This is an
% extention of Lucio's solution.

a = false(max(Points),1);
a(nonzeros(Points)) = true;
t1 = [1 NaN];% These two are used in the augmented code below.
cnt = 1;%

for i = 1:N-1
    a(bsxfun(@plus,find(a),Points)) = true;
    t2 = t1;  %  Start augmented code.
    t1 = find(~a)'; % t1,t2 Successive vectors for successive #'s of q's.
    if ~isempty(t1) &amp;&amp; ~isempty(t2) &amp;&amp; numel(t1)==numel(t2) &amp;&amp; t2(end)==(t1(end)-Points(end))
        cnt = cnt + 1;
        if cnt == 3
            vct = t1~=t2;
            t2(vct) = t2(vct) + (N-i)* Points(end);
            nonScores4 = t2;
            return % We can skip the rest of the iterations.
        end
    end  % End augmented code.
end

nonScores4 = find(~a)';

</code> </pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: Ilya Rozenfeld</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29922</link>
		<dc:creator>Ilya Rozenfeld</dc:creator>
		<pubDate>Tue, 09 Dec 2008 15:15:52 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29922</guid>
		<description>I've just noticed that my solution can be greatly improved by replacing this line

allAnswrs = ...
    arrayfun(@(x) double(dec2base(x,base, numAnswrs)) - charShft, ...
    (minNum : maxNum).', 'UniformOutput', false);

with

allAnswrs = ...
    arrayfun(@(x) double(dec2base(x,base, numAnswrs)) - charShft, ...
    (minNum : numQuests : maxNum).', 'UniformOutput', false);</description>
		<content:encoded><![CDATA[<p>I&#8217;ve just noticed that my solution can be greatly improved by replacing this line</p>
<p>allAnswrs = &#8230;<br />
    arrayfun(@(x) double(dec2base(x,base, numAnswrs)) - charShft, &#8230;<br />
    (minNum : maxNum).&#8217;, &#8216;UniformOutput&#8217;, false);</p>
<p>with</p>
<p>allAnswrs = &#8230;<br />
    arrayfun(@(x) double(dec2base(x,base, numAnswrs)) - charShft, &#8230;<br />
    (minNum : numQuests : maxNum).&#8217;, &#8216;UniformOutput&#8217;, false);</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Ilya Rozenfeld</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29921</link>
		<dc:creator>Ilya Rozenfeld</dc:creator>
		<pubDate>Tue, 09 Dec 2008 14:43:30 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29921</guid>
		<description>Here is another solution.  It is based on conversion of the numbers with different bases.  Unfotunatley, I don't think it scales well for larger problems.  Anyway, here it goes

numQuests = 7;
numAnswrs = 4;
Points = [0 3 5 8];

base = numQuests + 1;
minNum = numQuests;
maxNum = numQuests * base^(numAnswrs-1);
charShft = 48;

allAnswrs = ...
    arrayfun(@(x) double(dec2base(x,base, numAnswrs)) - charShft, ...
    (minNum : maxNum).', 'UniformOutput', false);

indx = cellfun(@(x) sum(x) == numQuests, allAnswrs);

Feasible = unique(cat(1, allAnswrs{indx}) * Points(:));
notFeasible = setdiff(min(Points)*numQuests : max(Points)*numQuests, Feasible);</description>
		<content:encoded><![CDATA[<p>Here is another solution.  It is based on conversion of the numbers with different bases.  Unfotunatley, I don&#8217;t think it scales well for larger problems.  Anyway, here it goes</p>
<p>numQuests = 7;<br />
numAnswrs = 4;<br />
Points = [0 3 5 8];</p>
<p>base = numQuests + 1;<br />
minNum = numQuests;<br />
maxNum = numQuests * base^(numAnswrs-1);<br />
charShft = 48;</p>
<p>allAnswrs = &#8230;<br />
    arrayfun(@(x) double(dec2base(x,base, numAnswrs)) - charShft, &#8230;<br />
    (minNum : maxNum).&#8217;, &#8216;UniformOutput&#8217;, false);</p>
<p>indx = cellfun(@(x) sum(x) == numQuests, allAnswrs);</p>
<p>Feasible = unique(cat(1, allAnswrs{indx}) * Points(:));<br />
notFeasible = setdiff(min(Points)*numQuests : max(Points)*numQuests, Feasible);</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Lucio</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29919</link>
		<dc:creator>Lucio</dc:creator>
		<pubDate>Mon, 08 Dec 2008 17:29:10 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29919</guid>
		<description>Daniel:

The key point of my solution is to use matrix exponentiation as the propagation algorithm, for this we need to start with an adjacency matrix. A non-zero entry in the (i,j) row-column indicates that the total cumulative score can change from (i-1) to (j-1) after considering the n-th question. Note that we need to make the score=index+1 because we need to have a score of zero also. 
 
If you had the Bioinformatics Toolbox you could have propagated using "Breadth First Search":

&lt;pre&gt;
maxscorep1 = N*max(Points)+1;
A = toeplitz(sparse(1,1,1,1,maxscorep1),sparse(1,Points+1,1,1,maxscorep1));
setdiff(1:maxscorep1,graphtraverse(A,1,'Method','BFS','Depth',N))-1


I used the TOEPLITZ function to create the required adjacency matrix. On purpose I used sparse indices, so the Toeplitz matrix is also sparse, as the particular adjacency matrix has many zeros, this allows to scale up the problem. A full matrix would have looked:

&lt;pre&gt;
A = toeplitz([1;zeros(maxscorep1-1,1)],[1 0 0 1 0 1 0 0 1 zeros(1,maxscorep1-9)])


I need to admit that the solution with CONV previously posted is very elegant, perhaps it is possible to express a convolution in terms of a toeplitz matrix.

Lucio</description>
		<content:encoded><![CDATA[<p>Daniel:</p>
<p>The key point of my solution is to use matrix exponentiation as the propagation algorithm, for this we need to start with an adjacency matrix. A non-zero entry in the (i,j) row-column indicates that the total cumulative score can change from (i-1) to (j-1) after considering the n-th question. Note that we need to make the score=index+1 because we need to have a score of zero also. </p>
<p>If you had the Bioinformatics Toolbox you could have propagated using &#8220;Breadth First Search&#8221;:</p>
<pre>
maxscorep1 = N*max(Points)+1;<br />
A = toeplitz(sparse(1,1,1,1,maxscorep1),sparse(1,Points+1,1,1,maxscorep1));<br />
setdiff(1:maxscorep1,graphtraverse(A,1,&#8217;Method&#8217;,'BFS&#8217;,'Depth&#8217;,N))-1
<p>I used the TOEPLITZ function to create the required adjacency matrix. On purpose I used sparse indices, so the Toeplitz matrix is also sparse, as the particular adjacency matrix has many zeros, this allows to scale up the problem. A full matrix would have looked:</p>
</pre><pre>
A = toeplitz([1;zeros(maxscorep1-1,1)],[1 0 0 1 0 1 0 0 1 zeros(1,maxscorep1-9)])
<p>I need to admit that the solution with CONV previously posted is very elegant, perhaps it is possible to express a convolution in terms of a toeplitz matrix.</p>
<p>Lucio</p>
</pre>]]></content:encoded>
	</item>
	<item>
		<title>By: Daniel Armyr</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29918</link>
		<dc:creator>Daniel Armyr</dc:creator>
		<pubDate>Fri, 05 Dec 2008 07:54:30 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29918</guid>
		<description>So, could someone explain what the toeplitz function represents in this situation?

--DA</description>
		<content:encoded><![CDATA[<p>So, could someone explain what the toeplitz function represents in this situation?</p>
<p>&#8211;DA</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: John DErrico</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29912</link>
		<dc:creator>John DErrico</dc:creator>
		<pubDate>Wed, 03 Dec 2008 19:40:22 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29912</guid>
		<description>The problem with any method that uses exhaustive searches via ndgrid is the method will always fail for large problems. In these cases a recursive methodology is often better. (Really, this is just a variation on my partitions code on the FEX to find the partitions of an integer.) Consider the feasibleTestScores function.

&lt;pre&gt;
function Feasible = feasibleTestScores(scores,problemscores,nprobs)
% uses recursive methodology to identify which test scores are achievable
%
% scores - a list of scores to test for feasibility.
%          All elements of scores must be non-negative integers
%
% problemscores - the possible (all integers) scores for each
%          problem in the test.
%
% nprobs - the number of problems in the overall test
%
% Feasible = logical vector, true where a score was feasible

scoresize = size(scores);
scores = scores(:);

problemscores = sort(problemscores(:),1,'descend');

% maximum possible score to worry about
maxscore = max(scores);

if maxscore&#60;min(problemscores)
  Feasible = false(scoresize);
  return
elseif (maxscore == 0) &#38;&#38; ismember(problemscores,0)
  Feasible = true(scoresize);
  return
elseif ((nprobs*problemscores(1)) &#60; min(scores))
  Feasible = false(scoresize);
  return
elseif (nprobs==0)
  Feasible = true(scores==0);
  return
end

% check each potential number of scores for
% the largest (first element of) problemscores.
% Note that we don't need to worry about
% problemscores(1) being zero here.
n = min(nprobs,floor(maxscore/problemscores(1)));
Feasible = false(size(scores));
for i = 0:n
  Feasible = Feasible &#124; ((i*problemscores(1)) == scores);
  k = ((i*problemscores(1)) &#60; scores);
  if any(k)
    Feasible(k) = Feasible(k) &#124; feasibleTestScores( ...
      scores(k)-i*problemscores(1),problemscores(2:end), ...
      nprobs-i);
  end
end
Feasible = reshape(Feasible,scoresize);
&lt;/pre&gt;

Test it out:
&lt;pre&gt;
s = 0:20;
b = feasibleTestScores(s,[0 3 5 10],2);s(b)
ans =
     0     3     5     6     8    10    13    15    20
&lt;/pre&gt;

Thus, for only two problems, we can achieve 9 of the potential scores 0:20.

What happens when we have a test with 50 problems? Do you want to generate a grid with 4^50 elements in it? NO!!! How long does the recursive solution take?

&lt;pre&gt;
tic,b = feasibleTestScores(0:500,[0 3 5 10],50);toc
Elapsed time is 1.282112 seconds.
&lt;/pre&gt;

Of the potential scores tested, how many were possible?

&lt;pre&gt;
sum(b)
ans =
   485
&lt;/pre&gt;</description>
		<content:encoded><![CDATA[<p>The problem with any method that uses exhaustive searches via ndgrid is the method will always fail for large problems. In these cases a recursive methodology is often better. (Really, this is just a variation on my partitions code on the FEX to find the partitions of an integer.) Consider the feasibleTestScores function.</p>
<pre>
function Feasible = feasibleTestScores(scores,problemscores,nprobs)
% uses recursive methodology to identify which test scores are achievable
%
% scores - a list of scores to test for feasibility.
%          All elements of scores must be non-negative integers
%
% problemscores - the possible (all integers) scores for each
%          problem in the test.
%
% nprobs - the number of problems in the overall test
%
% Feasible = logical vector, true where a score was feasible

scoresize = size(scores);
scores = scores(:);

problemscores = sort(problemscores(:),1,'descend');

% maximum possible score to worry about
maxscore = max(scores);

if maxscore&lt;min(problemscores)
  Feasible = false(scoresize);
  return
elseif (maxscore == 0) &amp;&amp; ismember(problemscores,0)
  Feasible = true(scoresize);
  return
elseif ((nprobs*problemscores(1)) &lt; min(scores))
  Feasible = false(scoresize);
  return
elseif (nprobs==0)
  Feasible = true(scores==0);
  return
end

% check each potential number of scores for
% the largest (first element of) problemscores.
% Note that we don't need to worry about
% problemscores(1) being zero here.
n = min(nprobs,floor(maxscore/problemscores(1)));
Feasible = false(size(scores));
for i = 0:n
  Feasible = Feasible | ((i*problemscores(1)) == scores);
  k = ((i*problemscores(1)) &lt; scores);
  if any(k)
    Feasible(k) = Feasible(k) | feasibleTestScores( ...
      scores(k)-i*problemscores(1),problemscores(2:end), ...
      nprobs-i);
  end
end
Feasible = reshape(Feasible,scoresize);
</pre>
<p>Test it out:</p>
<pre>
s = 0:20;
b = feasibleTestScores(s,[0 3 5 10],2);s(b)
ans =
     0     3     5     6     8    10    13    15    20
</pre>
<p>Thus, for only two problems, we can achieve 9 of the potential scores 0:20.</p>
<p>What happens when we have a test with 50 problems? Do you want to generate a grid with 4^50 elements in it? NO!!! How long does the recursive solution take?</p>
<pre>
tic,b = feasibleTestScores(0:500,[0 3 5 10],50);toc
Elapsed time is 1.282112 seconds.
</pre>
<p>Of the potential scores tested, how many were possible?</p>
<pre>
sum(b)
ans =
   485
</pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tom Richardson</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29910</link>
		<dc:creator>Tom Richardson</dc:creator>
		<pubDate>Wed, 03 Dec 2008 15:54:41 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29910</guid>
		<description>Here are time results for the generating function solution for N = 100 to 1000,by 100's, using a slightly bigger score set. The '/5' operation after convolution is to avoid overflow in q for N &#62; 400. The number of convolutions could be cut from N to log N in the usual way, which might speed things up.

&lt;pre&gt;
result = {}; 
for N = 100:100:1000 
  tic; 
  p = []; 
  p([0 5 11 17 23 29] + 1) = 1;  
  q = 1; 
  for k=1:N 
    q = conv(p,q)/5; 
  end; 
  result{end+1} = find(~q) - 1; 
  toc; 
end
Elapsed time is 0.042640 seconds.
Elapsed time is 0.157314 seconds.
Elapsed time is 0.292813 seconds.
Elapsed time is 0.500169 seconds.
Elapsed time is 0.852585 seconds.
Elapsed time is 1.383100 seconds.
Elapsed time is 2.101764 seconds.
Elapsed time is 2.867327 seconds.
Elapsed time is 3.846593 seconds.
Elapsed time is 4.823939 seconds.
&lt;/pre&gt;</description>
		<content:encoded><![CDATA[<p>Here are time results for the generating function solution for N = 100 to 1000,by 100&#8217;s, using a slightly bigger score set. The &#8216;/5&#8242; operation after convolution is to avoid overflow in q for N &gt; 400. The number of convolutions could be cut from N to log N in the usual way, which might speed things up.</p>
<pre>
result = {};
for N = 100:100:1000
  tic;
  p = [];
  p([0 5 11 17 23 29] + 1) = 1;
  q = 1;
  for k=1:N
    q = conv(p,q)/5;
  end;
  result{end+1} = find(~q) - 1;
  toc;
end
Elapsed time is 0.042640 seconds.
Elapsed time is 0.157314 seconds.
Elapsed time is 0.292813 seconds.
Elapsed time is 0.500169 seconds.
Elapsed time is 0.852585 seconds.
Elapsed time is 1.383100 seconds.
Elapsed time is 2.101764 seconds.
Elapsed time is 2.867327 seconds.
Elapsed time is 3.846593 seconds.
Elapsed time is 4.823939 seconds.
</pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: Gautam Vallabha</title>
		<link>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29907</link>
		<dc:creator>Gautam Vallabha</dc:creator>
		<pubDate>Wed, 03 Dec 2008 03:03:26 +0000</pubDate>
		<guid>http://blogs.mathworks.com/loren/2008/12/02/possible-test-scores/#comment-29907</guid>
		<description>Walter's solution is O(K^N), where K is the number of choices per question and N is the number of questions. With a slight modification, we can get a O(N^K) solution, a substantial improvement if N is assumed to vary widely. 

Let k1 = score for choice 1, k2 = score for choice 2, etc, and a1 = # of times choice 1 was chosen, a2 = # of times choice 2 was chosen, etc. 
&lt;pre&gt;
 Essentially, we want to all possible values of 
   k1*a1 + k2*a2 + k3*a3 + k4*a4 
 that satisfy the constraint
    a1 + a2 + a3 + a4 = N
&lt;/pre&gt;

The constraint can be enumerated and evaluated using NDGRID, as in Walter's solution. Note that the NDGRID output has dimension K (the # of choices per question) rather than N (the number of questions).
&lt;pre&gt;
% setup 
Points = [0 3 5 8];
K = numel(Points);
N = 7;
% solve
[A{1:K}] = ndgrid(0:N);
combinations = cell2mat(cellfun(@(x)x(:),A,'unif',false));
indices = find(sum(combinations,2) == N);
possibleSums = unique(combinations(indices,:) * Points');
maximumValue = max(Points)*N;
setdiff(0:maximumValue,possibleSums)
&lt;/pre&gt;

Answers for various N:
&lt;pre&gt;
N=7
     1     2     4     7    49    52    54    55
N=15
     1     2     4     7   113   116   118   119
N=30
     1     2     4     7   233   236   238   239
N=40
     1     2     4     7   313   316   318   319
&lt;/pre&gt;

I got out-of-memory errors for N=60. It would be interesting to see where the various algorithms break down. With Lucio's second solution, I went up to N=100 without much of a problem, and I could probably go much higher.</description>
		<content:encoded><![CDATA[<p>Walter&#8217;s solution is O(K^N), where K is the number of choices per question and N is the number of questions. With a slight modification, we can get a O(N^K) solution, a substantial improvement if N is assumed to vary widely. </p>
<p>Let k1 = score for choice 1, k2 = score for choice 2, etc, and a1 = # of times choice 1 was chosen, a2 = # of times choice 2 was chosen, etc. </p>
<pre>
 Essentially, we want to all possible values of
   k1*a1 + k2*a2 + k3*a3 + k4*a4
 that satisfy the constraint
    a1 + a2 + a3 + a4 = N
</pre>
<p>The constraint can be enumerated and evaluated using NDGRID, as in Walter&#8217;s solution. Note that the NDGRID output has dimension K (the # of choices per question) rather than N (the number of questions).</p>
<pre>
% setup
Points = [0 3 5 8];
K = numel(Points);
N = 7;
% solve
[A{1:K}] = ndgrid(0:N);
combinations = cell2mat(cellfun(@(x)x(:),A,'unif',false));
indices = find(sum(combinations,2) == N);
possibleSums = unique(combinations(indices,:) * Points');
maximumValue = max(Points)*N;
setdiff(0:maximumValue,possibleSums)
</pre>
<p>Answers for various N:</p>
<pre>
N=7
     1     2     4     7    49    52    54    55
N=15
     1     2     4     7   113   116   118   119
N=30
     1     2     4     7   233   236   238   239
N=40
     1     2     4     7   313   316   318   319
</pre>
<p>I got out-of-memory errors for N=60. It would be interesting to see where the various algorithms break down. With Lucio&#8217;s second solution, I went up to N=100 without much of a problem, and I could probably go much higher.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
