[BZOJ2239]猜谜语

来源:互联网 发布:angular.js官网 编辑:程序博客网 时间:2024/05/06 10:53
题目描述
给出一个长度为N的数字字符串和一个数字T,要求插入最少的加号或者乘号,使得数字字符串的运算结果为T。运算符*号优先级高于+号,运算数可以有任意个前导0.

输入
输入不超过5组数据,每组数据两行。
每组数据的第一行为长度N,只包含0~9的数字字符串;第二行为一个数字T。
输入T<0表示输入结束。

输出
输出一个数字单独占一行,表示最少需要添加的运算符(+号或*号)数,无解输出-1.

样例输入
123 
123 
00000000000000000 
992299 
40
032089
5
333
9
00
-1

样例输出
0
0
5
3
2

提示
对于30%的数据,有1<=N<=10,0<=T<=50.
对于50%的数据,有1<=N<=15,0<=T<=200.
对于全部的数据,有1<=N<=20,0<=T<=250.


题解:
分为两步: 
第一步处理只有乘号的情况: 
dp[i][j][k]: 从第i个数字, 到第j个数字, 运算结果为k时, 所需要添加的最少乘号个数。 
dp[i][j][k]=min( dp[i][j][k], dp[i][p][x]+1 )  ( i<=p<j, k整除x且x=k/num[p+1][j] ) 
num[p+1][j]为从第p+1个数字到第j个数字组成的数的值。 
初始值为dp[i][j][num[i][j]]=0 
注意num[p+1][j]为0时要特别处理, 因为乘法中乘一个0就是0了 
  
第二步处理有乘号和加号的情况: 
G[i][j]: 前i个字符, 运算结果为j时, 需要添加的最少的运算符个数。 
G[i][j]=min( G[i][j], G[k][j-x]+dp[k+1][i][x]+1 ) ( 0<=k<i, 0<=x<=j ) 
初始值G[i][j]=dp[0][i][j]


#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std;  const int INF=0x3f3f3f3f;     const int N=25;  const int M=255;  int n, T, num[N][N];  char s[N]; int dp[N][N][M], G[N][M];    int main() {     for(;;) {         scanf( "%s%d", s+1, &T );         if( T<0 ) break;         memset( num, -1, sizeof num );         memset( dp, 0x3f, sizeof dp );         memset( G, 0x3f, sizeof G ); G[0][0]=0;         n=strlen( s+1 );                   for( int i=1; i<=n; i++)              for( int j=i; j<=n; j++ ){                  int tmp=0;                  for( int k = i; k<=j; k++ )                      tmp=tmp*10+s[k]-'0';                  num[i][j]=tmp;                  if( 0<=tmp && tmp<=T) dp[i][j][tmp]=0;              }                    for( int i=1; i<=n; i++ )             for( int j=i; j<=n; j++ )                 for( int p=i; p<j; p++ ) {                     if( !num[p+1][j] ) dp[i][j][0]=min( dp[i][j][0], 1 );                     dp[i][j][0]=min( dp[i][j][0], dp[i][p][0]+1 );                     for( int k=1; k<=T; k++ )                         if( num[p+1][j]>0 && !( k%num[p+1][j] ) )                             dp[i][j][k]=min( dp[i][j][k], dp[i][p][ k/num[p+1][j] ]+1 );                 }                       for( int i=1; i<=n; i++ )             for( int j=0; j<=T; j++ )                 for( int k=0; k<i; k++ )                     for( int x=0; x<=j; x++ )                         G[i][j]=min( G[i][j], G[k][x]+dp[k+1][i][j-x]+1 );                   if( G[n][T]>=INF ) printf( "-1\n" );         else printf( "%d\n", G[n][T]-1 );     }     return 0; }


原创粉丝点击