Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>My short answer: in no way.</p> <p>Just because the problem definition is <strong>incorrect</strong>. As <a href="https://stackoverflow.com/users/497358/axn">Axn</a> brilliantly noticed:</p> <blockquote> <p>There is a little bit of contradiction going on in the requirement. It states that K &lt;= N. But as K approaches N, the frequency requirement will be contradicted by the Uniqueness requirement. Worst case, if K=N, all elements will be returned (i.e appear with same frequency), irrespective of their weight.</p> </blockquote> <p>Anyway, when K is pretty small relative to N, calculated frequencies will be pretty close to theoretical values.</p> <p>The task may be splitted on two subtasks:</p> <ol> <li>Generate random numbers with a given distribution (specified by weights)</li> <li>Generate unique random numbers</li> </ol> <h2>Generate random numbers with a given distribution</h2> <ol> <li>Calculate sum of weights (<code>sumOfWeights</code>)</li> <li>Generate random number from the range <code>[1; sumOfWeights]</code></li> <li>Find an array element where the sum of weights from the beginning of the array is greater than or equal to the generated random number</li> </ol> <p>Code</p> <pre><code>#include &lt;iostream&gt; #include &lt;cstdlib&gt; #include &lt;ctime&gt; // 0 - id, 1 - weight typedef unsigned Pair[2]; unsigned Random(Pair* i_set, unsigned* i_indexes, unsigned i_size) { unsigned sumOfWeights = 0; for (unsigned i = 0; i &lt; i_size; ++i) { const unsigned index = i_indexes[i]; sumOfWeights += i_set[index][2]; } const unsigned random = rand() % sumOfWeights + 1; sumOfWeights = 0; unsigned i = 0; for (; i &lt; i_size; ++i) { const unsigned index = i_indexes[i]; sumOfWeights += i_set[index][3]; if (sumOfWeights &gt;= random) { break; } } return i; } </code></pre> <h2>Generate unique random numbers</h2> <p>Well known Durstenfeld-Fisher-Yates algorithm may be used for generation unique random numbers. See <a href="https://stackoverflow.com/questions/196017/unique-random-numbers-in-o1">this great explanation</a>.</p> <p>It requires N bytes of space, so if N value is defined at compiled time, we are able to allocate necessary space at compile time.</p> <p>Now, we have to combine these two algorithms. We just need to use our own <code>Random()</code> function instead of standard <code>rand()</code> in unique numbers generation algorithm.</p> <p>Code</p> <pre><code>template&lt;unsigned N, unsigned K&gt; void Generate(Pair (&amp;i_set)[N], unsigned (&amp;o_res)[K]) { unsigned deck[N]; for (unsigned i = 0; i &lt; N; ++i) { deck[i] = i; } unsigned max = N - 1; for (unsigned i = 0; i &lt; K; ++i) { const unsigned index = Random(i_set, deck, max + 1); std::swap(deck[max], deck[index]); o_res[i] = i_set[deck[max]][0]; --max; } } </code></pre> <h2>Usage</h2> <pre><code>int main() { srand((unsigned)time(0)); const unsigned c_N = 5; // N const unsigned c_K = 2; // K Pair input[c_N] = {{0, 5}, {1, 3}, {2, 2}, {3, 5}, {4, 4}}; // input array unsigned result[c_K] = {}; const unsigned c_total = 1000000; // number of iterations unsigned counts[c_N] = {0}; // frequency counters for (unsigned i = 0; i &lt; c_total; ++i) { Generate&lt;c_N, c_K&gt;(input, result); for (unsigned j = 0; j &lt; c_K; ++j) { ++counts[result[j]]; } } unsigned sumOfWeights = 0; for (unsigned i = 0; i &lt; c_N; ++i) { sumOfWeights += input[i][1]; } for (unsigned i = 0; i &lt; c_N; ++i) { std::cout &lt;&lt; (double)counts[i]/c_K/c_total // empirical frequency &lt;&lt; " | " &lt;&lt; (double)input[i][1]/sumOfWeights // expected frequency &lt;&lt; std::endl; } return 0; } </code></pre> <h2>Output</h2> <pre><code>N = 5, K = 2 Frequencies Empiricical | Expected 0.253813 | 0.263158 0.16584 | 0.157895 0.113878 | 0.105263 0.253582 | 0.263158 0.212888 | 0.210526 </code></pre> <p>Corner case when weights are actually ignored</p> <pre><code>N = 5, K = 5 Frequencies Empiricical | Expected 0.2 | 0.263158 0.2 | 0.157895 0.2 | 0.105263 0.2 | 0.263158 0.2 | 0.210526 </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload