组合数学持续更新
poj 1664 放苹果
http://poj.org/problem?id=1664
一道基础的题目,dp[i][j]代表 i 个苹果 放到 j 个盘子的总类数目。
dp[ i ][ j ] = dp[ i ] [j -1 ] + dp[ i -j ][ j ];
分类讨论第j个盘子是否放了苹果。
没有放的时候 dp [ i ][ j-1 ]种,把i个苹果全部放在前 j -1 个盘子里;
放的时候,可能是放一个,可能是放多个,也就说我可以这样转化,先在所有的盘子上放上一个,然后,任意放。
即dp[ i - j ] [ j ].
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 3 int dp[11][11]; 4 void prepare() 5 { 6 int i,j; 7 // put i apples into j pans. 8 9 for(i=0;i<=10;i++) dp[0][i]=1; 10 for(i=1;i<=10;i++) 11 { 12 for(j=1;j<=10;j++) 13 if(j<=i) 14 dp[i][j]=dp[i][j-1]+dp[i-j][j]; 15 else 16 dp[i][j]=dp[i][j-1]; 17 } 18 } 19 int main() 20 { 21 int T; 22 int n,m; 23 prepare(); 24 scanf("%d",&T); 25 while(T--) 26 { 27 scanf("%d%d",&n,&m); 28 printf("%d\n",dp[n][m]); 29 } 30 return 0; 31 }
hdu 2512
一卡通大冒险
也是一道基础的题目。
dp[ i ] [ j ] 代表 i 个东西分成 j 个集合的方法数。
也对第j 个元素进行讨论。
dp[ i ] [j ] = dp [ i -1 ] [ j -1 ] + j* dp[ i -1][ j ];
方法同上,唯一不同在于 集合中没有排序。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<string.h> 3 4 int dp[2001][2001]; 5 void prepare() 6 { 7 int i,j; 8 dp[1][1]=1; 9 for(i=2;i<=2000;i++) 10 for(j=1;j<=i;j++) 11 dp[i][j]=(dp[i-1][j-1]+j*dp[i-1][j])%1000; 12 } 13 int main() 14 { 15 int T; 16 int n,i,cur; 17 scanf("%d",&T); 18 prepare(); 19 while(T--) 20 { 21 scanf("%d",&n); 22 cur=0; 23 for(i=1;i<=n;i++) 24 cur=(cur+dp[n][i])%1000; 25 printf("%d\n",cur); 26 } 27 return 0; 28 }
java代码,第一次写java代码哈哈。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //package day0; 2 import java.util.*; 3 4 public class Main { 5 6 static int dp[][]= new int[2001][2001]; 7 public static void main(String[] args) { 8 // TODO Auto-generated method stub 9 int T,t,n,cur,i; 10 fun(); 11 Scanner cin = new Scanner(System.in); 12 T = cin.nextInt(); 13 for(t=1;t<=T;t++) 14 { 15 n = cin.nextInt(); 16 cur = 0; 17 for(i=1;i<=n;i++) 18 cur=(cur+dp[n][i])%1000; 19 System.out.println(cur); 20 } 21 } 22 public static void fun() 23 { 24 int i,j; 25 dp[1][1]=1; 26 for(i=2;i<=2000;i++) 27 { 28 for(j=1;j<=i;j++) 29 dp[i][j]=(dp[i-1][j-1]+j*dp[i-1][j])%1000; 30 } 31 } 32 33 }
hdu 2085 核反应堆
基础题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 5 typedef __int64 LL; 6 7 LL dp[34][2]; 8 9 void prepare() 10 { 11 int i,j; 12 memset(dp,0,sizeof(dp)); 13 dp[0][1]=1;dp[0][0]=0; 14 dp[1][1]=3;dp[1][0]=1; 15 for(i=2;i<=33;i++) 16 { 17 dp[i][1]=3*dp[i-1][1]+2*dp[i-1][0]; 18 dp[i][0]=dp[i-1][1]+dp[i-1][0]; 19 } 20 } 21 int main() 22 { 23 int n; 24 prepare(); 25 while(scanf("%d",&n)>0) 26 { 27 if(n==-1)break; 28 printf("%I64d, %I64d\n",dp[n][1],dp[n][0]); 29 } 30 return 0; 31 }
hdu 3398 String
hdu 3944 dp?
hdu 3037 Saving Beans
nyoj 光棍节的快乐 组合+错排公式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 1、当N=1和2时,易得解~,假设F(N-1)和F(N-2)已经得到, 3 重点分析下面的情况: 4 2、当有N封信的时候,前面N-1封信可以有N-1或者 N-2封错装 5 3、前者,对于每种错装,可从N-1封信中任意取一封和第N封错装, 6 故=F(N-1)*(N-1) 7 4、后者简单,只能是没装错的那封和第N封交换信封, 8 没装错的那封可以是前面N-1封中的任意一个,故= F(N-2) * (N-1) 9 **/ 10 #include<stdio.h> 11 typedef long long LL; 12 LL dp[21]; 13 void init() 14 { 15 LL i; 16 dp[1]=0; 17 dp[2]=1; 18 for(i=3;i<=20;i++) 19 dp[i]=(i-1)*(dp[i-1]+dp[i-2]); 20 } 21 int main() 22 { 23 init(); 24 LL n,m; 25 LL i,j,sum,k; 26 while(scanf("%lld%lld",&n,&m)>0) 27 { 28 k=m; 29 if(m>n-m) m=n-m; 30 sum=1; 31 for(i=1,j=n;i<=m;j--,i++) 32 sum=sum*j/i; 33 printf("%lld\n",sum*dp[k]); 34 } 35 return 0; 36 }