Introduction

This is my blog of programming, I take notes and leave codes of computer science problems I solved here. Be my guest to comment :)

Friday, November 23, 2012

uva 1213 - Sum of Different Primes


/*
Problem link
Type: DP, Prime
Algorithm:
 Let f(i,j,k) is the number of way to split number i into j prime numbers 
 using the first k prime numbers
 
 If we decide to choose the kth prime in the sum, then the number of ways
 is f(i-Prime[k],j-1,k-1), that is, the number of way to split number
 i-Prime[k] into j-1 prime numbers (and the kth prime number) using 
 the first k-1 prime numbers (cannot choose Prime[k] again)
 
 If we decide not to choose the kth prime in the sum, then the number of ways
 is f(i,j,k-1), that is, the number of way to split number i into j prime numbers
 using the first k-1 prime number.
 
 Hence, f(i,j,k) = f(i-prime[k],j-1,k-1) + f(i,j,k-1);
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 1200;
//------------------------------
bool isPrime[maxn];
int Prime[maxn], f[maxn][20][197];
int n,k,m;
//------------------------------
void sieve();
void solve();
//------------------------------
int main() {
 sieve();
 while (true)
 {
  cin >> n >> k;
  if (n==0 && k==0) break;
  solve();
 }
 return 0;
}
//------------------------------
void sieve() {
 memset(isPrime,true,sizeof(isPrime));
 isPrime[1] = false;
 int i = 2;
 while (i<=int(sqrt(maxn)))
 {
  if (isPrime[i])
  {
   int j = i;
   while (j<=maxn)
   {
    j = j+i;
    isPrime[j] = false;
   }
  }
  i++;
 }
 m = 0;
 for (int i=2; i<=maxn; i++) 
  if (isPrime[i]) Prime[++m] = i;
}
//------------------------------
void solve() {
 for (int i=0; i<=n; i++)
  for (int j=0; j<=k; j++)
   for (int h=0; h<=m; h++) f[i][j][h] = 0;
 
 for (int i=1; i<=n; i++)
  if (isPrime[i])
   for (int j=1; j<=m; j++)
   {
    if (Prime[j]<i) continue;
    else if (Prime[j]>=i) f[i][1][j] = 1;
   }
   
 for (int i=1; i<=n; i++)
  for (int j=2; j<=k; j++)
   for (int h=1; h<=m; h++)
   {
    if (Prime[h]<=i) f[i][j][h] = f[i-Prime[h]][j-1][h-1]+f[i][j][h-1];
    else f[i][j][h] = f[i][j][h-1];
   }
 int i;
 for (i=m; i>=1; i--)
  if (Prime[i]<=n) break;
 cout << f[n][k][i] << endl;
}
//------------------------------

5 comments:

  1. Hi. I have a question because it's hard for me to understand how it's work even with code and description. Like for example lets say I have a state f[6][3][2]. What does it means? Is it means that this cell will hold the number of ways to split 6 into three prime numbers using first two prime numbers? Some of the states doesn't make sense to me. I'm sure its good code i just don't understand.

    ReplyDelete
    Replies
    1. Yes, you are correct. f[6][3][2] means the number of ways to split 6 into 3 prime numbers using the first 2 prime numbers (2 and 3). In this case, there's only 1 way: 6 = 2 + 2 + 2

      Delete
    2. Hi. I'm not sure but I think you are incorrect because if I understand the problem correctly in this problem you can only use different primes to split the number or I'm wrong? I think that you cannot use the same prime number in the solution? You can only use unique primes in the solution.

      Delete
    3. Yes you are correct, my mistake. So that means f[6][3][2] is 0, there's no way to split 6 into 3 different primes using the first 2 prime numbers. Hence in the formula, f[i-Prime[h]][j-1][h-1]+f[i][j][h-1], the "h-1" part will avoid duplication of primes.

      Delete
    4. Thanks for your quick reply. I think I'm starting to understand it a little better.

      Delete