遞推3--位數問題
阿新 • • 發佈:2017-06-13
推導 邊界條件 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 intans=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--位數問題