背包型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 }