背包型dp/sgu 116 Index of super-prime

题意

  首先定义超级素数:2 3 5 7...这些都是素数,当这个数是素数且这个数在这个素数列里的第素数个位置,则为超级素数

  例如,3在第2个,是超级素数;7在第4个,由于4不是素数,所以7不是超级素数

  现在给定一个数n,求n最少能被几个超级素数之和表示,输出个数,并输出这几个超级素数

  如果不能表示为几个超级素数之和,输出0

分析

  首先,利用筛法可以求出1~n内的超级素数,显然,需要用到的素数绝对不会超过n

  (当然你也可以直接打表)

  预处理做好了,下面就是完全背包

  f[i]表示i最少能由f[i]个超级素数表示

  所求即为f[n]

  初始f[0]=0

  方程为f[j]=min{f[j-prime[i]]+1}

  至于记录路径 则再开一个数组from,from[i]表示i是由from[i]加上某个超级素数得来,输出时输出i-from[i]即可

Accepted Code

 1 /*
 2     PROBLEM:sgu116
 3     AUTHER:Rinyo
 4     MEMO:背包型dp 质数
 5 */
 6 
 7 #include<cstdio>
 8 const int oo=9999999;
 9 int n,len,tot;
10 int prime[10030],f[10030],from[10030];
11 
12 int isprime(int n)
13 {
14     if (n<2) return 0;
15     for (int i=2;i*i<=n;i++)
16         if (n%i==0) return 0;
17     return 1;
18 }
19 int main()
20 {
21     scanf("%d",&n);
22     tot=0;
23     for (int i=2;i<=n;i++)
24         if (isprime(i))
25         {
26             len++;
27             if (isprime(len)) {tot++;prime[tot]=i;}
28         }
29     for (int i=1;i<=n;i++) f[i]=oo;
30     for (int i=1;i<=tot;i++)
31         for (int j=prime[i];j<=n;j++)
32             if (f[j-prime[i]]+1<f[j])
33             {
34                 f[j]=f[j-prime[i]]+1;
35                 from[j]=j-prime[i];
36             }
37     if (f[n]==oo) printf("0");
38     else
39     {
40         printf("%d\n%d",f[n],n-from[n]);
41         for (int i=from[n];i;i=from[i]) printf(" %d",i-from[i]);
42         printf("\n");
43     }
44     return 0;
45 }

 

posted @ 2012-12-19 21:27  Rinyo  阅读(350)  评论(0编辑  收藏  举报