1. 程式人生 > >遞推3--位數問題

遞推3--位數問題

推導 邊界條件 iostream define 打印 name end pac calc

遞推3--位數問題

一、心得

問題想清楚

註意邊界

二、題目及分析

技術分享

技術分享

三、代碼及結果

方法一:排列組合

  1 /*
  2 位數問題 :
  3 在所有的n位數中,有多少個數中有偶數個數字3?
  4 
  5 方法一:
  6 排列組合
  7 n位數中有x個三的情況為:c(n,x)*9^(n-x) 
  8 還要減去首位為0的情況:c(n-1,x)*9^(n-1-x) 
  9 故為: c(n,x)*9^(n-x)- c(n-1,x)*9^(n-1-x) 
 10 calc[n][x]= c(n,x)*9^(n-x)
 11 dp[n][x]= c(n,x)*9^(n-x)- c(n-1,x)*9^(n-1-x)
12 dp[n][x]: n位數中有x個三的情況數目 13 14 15 方法二: 16 遞推 17 18 19 */ 20 21 /* 22 算法優化後面再看,先把基礎功能實現 23 */ 24 #include <iostream> 25 #define Max 10 26 using namespace std; 27 int dp[Max];//n位數中有x個三的情況數目 28 29 30 //求c(n,x) 31 int combination(int n,int x){ 32 /* 33 c(5,3)=(5*4*3)/(3*2*1)
34 */ 35 int ans=1; 36 if(n<x) return 0; 37 else if(n==x) return 1; 38 else{ 39 for(int i=n,j=1;j<=x;j++,i--){ 40 ans=ans*i/j;//這樣一定能除盡 41 } 42 } 43 return ans; 44 } 45 46 //計算c(n,x)*9^(n-x) 47 int calcTimes(int n,int x){ 48 int
ans=combination(n,x); 49 for(int i=1;i<=n-x;i++){ 50 ans*=9; 51 } 52 return ans; 53 } 54 55 //dp操作,沒做初始化,因為全局變量都是0, 56 void dpOperation(int n){ 57 for(int i=0;i<=n;i++){ 58 if(n==1){//一位數的話,第一位可以是0 59 dp[i]=calcTimes(n,i); 60 } 61 else if(n>1){ 62 dp[i]=calcTimes(n,i)-calcTimes(n-1,i); 63 } 64 } 65 66 // for(int i=1;i<=n;i++){//計算1-n位數的情況 67 // for(int j=0;j<=i;j++){//計算i位數有j個3的情況 68 // 69 // } 70 // } 71 } 72 73 //打印dp數組 74 void print(int n){ 75 for(int i=0;i<=n;i++){ 76 cout<<n<<"位數中有"<<i<<"個3的數目:"<<dp[i]<<" "<<endl; 77 } 78 cout<<endl; 79 } 80 81 //計算偶數個3 82 int even3(int n){ 83 int ans=0; 84 for(int i=0;i<=n;i++){ 85 if(i%2==0){ 86 ans+=dp[i]; 87 } 88 } 89 return ans; 90 } 91 92 93 int main(){ 94 int n=6; 95 //int ans=combination(10,7); 96 //int ans=calcTimes(2,2); 97 //cout<<ans<<endl; 98 dpOperation(n);//dp操作,沒做初始化,因為全局變量都是0, 99 //cout<<calcTimes(n,0)<<" "<<calcTimes(n-1,0)<<endl; 100 print(n);//打印dp數組 101 int ans=even3(n);//計算偶數個3 102 cout<<n<<"位數中有偶數個3的數目:"<<ans<<endl; 103 return 0; 104 }

技術分享

技術分享

方法二、遞推

 1 /*
 2 位數問題 :
 3 在所有的n位數中,有多少個數中有偶數個數字3?
 4 
 5 方法一:
 6 排列組合
 7 n位數中有x個三的情況為:c(n,x)*9^(n-x) 
 8 還要減去首位為0的情況:c(n-1,x)*9^(n-1-x) 
 9 故為: c(n,x)*9^(n-x)- c(n-1,x)*9^(n-1-x) 
10 calc[n][x]= c(n,x)*9^(n-x)
11 dp[n][x]= c(n,x)*9^(n-x)- c(n-1,x)*9^(n-1-x)
12 dp[n][x]: n位數中有x個三的情況數目 
13  
14 
15 方法二:
16 遞推
17 這種題目一般都是從i-1位推導第i位,就是看第n位取不取3 
18 
19 f[i][0]表示前i位取偶數個3有幾種情況
20 f[i][1]表示前i位取奇數個3有幾種情況 
21 則狀態轉移方程為:
22 f[i][0]=f[i-1][0]*9+f[i-1][1] 
23 f[i][1]=f[i-1][1]*9+f[i-1][0] 
24 邊界條件:f[1][1]=1 f[1][0]=9
25 其實可以看做是取完最後一位取第一位,而0不能做第一位,所以到n的時候,是*8 
26  
27  
28 */ 
29 
30 /*
31 算法優化後面再看,先把基礎功能實現 
32 */
33 #include <iostream>
34 using namespace std;
35 int main(){
36     int n;
37     int f[1005][2]={0};
38     cin>>n;
39     f[1][1]=1; 
40     f[1][0]=9;
41     for(int i=2;i<=n;i++){
42         int x=f[1][0];
43         if(i==n) x--;//其實可以看做是取完最後一位取第一位,而0不能做第一位,所以到n的時候,是*8 
44         f[i][0]=(f[i-1][0]*x+f[i-1][1])%12345; 
45         f[i][1]=(f[i-1][1]*x+f[i-1][0])%12345; 
46     } 
47     cout<<f[n][0]<<endl;
48     return 0;
49 } 

技術分享

遞推3--位數問題