题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4249
题目大意:给一个a+b=c的表达式,但是a、b、c中部分位的数字丢失,并用?代替,问有多少种方案使得这个表达式成立。
Sample Input
7+1?=1?
?1+?1=22
Sample Output
Case 1: 3
Case 2: 1
Hint
There are three solutions for the first case: 7+10=17, 7+11=18, 7+12=19 There is only one solution for the second case: 11+11=22 Note that 01+21=22 is not a valid solution because extra leading zeros are not allowed.
分析:网上的代码有2种,第一种:
状态dp[len][i][j][k]表示三个数a,b,c的len位上的三个数字i , j, k 。
if((i+j)%10==k) //上一位不进1
dp[len][i][j][k]+=dp[len-1][ii][jj][kk];其中ii+jj==kk||ii+jj+1==kk
if((i+j+1)%10==k) //上一位进1
dp[len][i][j][k]+=dp[len-1][ii][jj][kk];
其中ii+jj>=10&&(ii+jj)%10==kk,ii+jj+1>=0,(ii+jj+1)%10==kk
最后答案是sum(dp[len-1][i][j][k]), (i+j==k||i+j+1==k)
代码如下:
1 # include<iostream> 2 # include<cstring> 3 # include<cstdio> 4 # include<stack> 5 # include<algorithm> 6 # define LL __int64 //如果需要改成long long 的话多么方便 7 using namespace std; 8 9 int len1,len2,len3,a[10],b[10],c[10]; 10 LL dp[10][10][10][10]; 11 stack<char >st; 12 LL DP() 13 { 14 int i,j,k,l; 15 memset(dp,0,sizeof(dp)); 16 for(i=0; i<10; i++) 17 { 18 if(a[0] != -1 && a[0] != i) //枚举该位,如果不是?则必须是给定的数字i,不能枚举其他数 19 continue; 20 for(j=0; j<10; j++) 21 { 22 if(b[0] != -1 && b[0] != j) 23 continue; 24 for(k=0; k<10; k++) 25 { 26 if(c[0] != -1 && c[0] != k) 27 continue; 28 if((i+j)%10==k) 29 dp[0][i][j][k] = 1; 30 } 31 } 32 } 33 for(l=1; l<len3; l++) //从和的倒数第2位开始枚举 34 { 35 for(i=0; i<10; i++) 36 { 37 if(a[l] != -1 && a[l] != i) 38 continue; 39 if(l==len1-1 && i==0) //首位不能是0 40 continue; 41 if(l>=len1 && i!=0) //和比加数多余的位,相当于在加数的前面加0 42 continue; 43 for(j=0; j<10; j++) 44 { 45 if(b[l] !=-1 && b[l] !=j) 46 continue; 47 if(l==len2-1 && j==0) 48 continue; 49 if(l>=len2 && j!=0) 50 continue; 51 for(k=0; k<10; k++) 52 { 53 if(c[l] != -1 && c[l] !=k) 54 continue; 55 if(l==len3-1 && k==0) 56 continue; 57 if((i+j)%10 !=k &&(i+j+1)%10!=k) //因为对应位上的三个数字a+b=c或者a+b+1=c;是从前往后进位的 58 continue; 59 if((i+j)%10==k) //上一位不进1 60 { 61 for(int ii=0; ii<10; ii++) 62 for(int jj=0; jj<10; jj++) 63 for(int kk=0; kk<10; kk++) 64 { 65 if(dp[l-1][ii][jj][kk] !=0 &&(ii+jj==kk||ii+jj+1==kk)) 66 dp[l][i][j][k] += dp[l-1][ii][jj][kk]; 67 } 68 } 69 if((i+j+1)%10==k) //上一位进1 70 { 71 for(int ii=0; ii<10; ii++)ii+jj 72 for(int jj=0; jj<10; jj++) 73 for(int kk=0; kk<10; kk++) 74 { 75 if(dp[l-1][ii][jj][kk] !=0 &&(((ii+jj>=10 && (ii+jj)%10==kk))||(ii+jj+1>=10 &&(ii+jj+1)%10==kk))) 76 dp[l][i][j][k] += dp[l-1][ii][jj][kk]; 77 } 78 } 79 } 80 } 81 } 82 } 83 LL ans = 0; 84 for(i=0; i<10 ; i++) 85 for(j=0; j<10; j++) 86 for(k=0; k<10; k++) 87 { 88 if(dp[len3-1][i][j][k] != 0 && (i+j==k || i+j+1==k)) 89 ans += dp[len3-1][i][j][k]; 90 } 91 return ans; 92 } 93 int main() 94 { 95 char s[50]; 96 int cas=1; 97 while(~scanf("%s",s)) 98 { 99 int i,len = strlen(s); 100 memset(a,0,sizeof(a)); 101 memset(b,0,sizeof(b)); 102 memset(c,0,sizeof(c)); 103 for(i=0; s[i]!='+'; i++) 104 st.push(s[i]); 105 len1 = 0; 106 while(!st.empty()) //提取第一个加数,逆序存放到a数组里边,这样进位就是从前往后进位 107 { 108 if(st.top() != '?') 109 a[len1++] = st.top()-'0'; 110 else a[len1++] = -1; 111 st.pop(); 112 } 113 for(i++; s[i] != '='; i++) 114 st.push(s[i]); 115 len2 = 0; 116 while(!st.empty()) //提取第2个加数 117 { 118 if(st.top() != '?') 119 b[len2++] = st.top() - '0'; 120 else b[len2++] = -1; 121 st.pop(); 122 } 123 for(i++; i<len; i++) 124 st.push(s[i]); 125 len3 = 0; 126 while(!st.empty()) //提取第3个加数 127 { 128 if(st.top() != '?') 129 c[len3++] = st.top() - '0'; 130 else c[len3++] = -1; 131 st.pop(); 132 } 133 printf("Case %d: %I64d ",cas++,DP()); 134 } 135 return 0; 136 }