HDU 4294 A Famous Equation(DP)

题目链接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 }
原文地址:https://www.cnblogs.com/acm-bingzi/p/3305967.html