Fragrant numbers(dfs爆搜+区间dp+stoi)

Fragrant numbers(dfs爆搜+区间dp)

题意:给出一个以 "1145141919 " 无限循环的字符串,可以在合适的位置添加 ' + ' , ' * ' 和 ' ( ' , ' ) ' 将其转换为表达式进行运算,给了一个n,问最少需要前几个字符来构成n?

题解:(dfs)爆搜+区间dp:(dp[l][r])记录字符串(l)到(r)之间可以产生的数,用(set)类型来自动去重,具体见代码:

AC_Code:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 typedef long double ld;
 5 #define endl '
'
 6 const int inf=0x3f3f3f3f;
 7 const int maxn=1e5+10;
 8 
 9 
10 string st=" 11451419191145141919";  //注意前面一个空格,因为我们区间的下标是从1开始的
11 int ans[maxn];
12 set<int>dp[20][20];
13 
14 void dfs(int l,int r){
15     if( dp[l][r].size() ) return ;  //dp[l][r].size()不为0说明已经存入了数据了
16     int len=r-l+1;
17     if( len<=4 ){   //如果大于4了就一定大于题目所给的5000了必须拆开,小于等于4可以不用拆开
18         int num=stoi(st.substr(l,r-l+1));//stoi:把字符串化成十进制
19         if( num<=5000 ) dp[l][r].insert(num);
20     }
21     for(int i=l;i<r;i++){
22         dfs(l,i);
23         dfs(i+1,r);
24         for(int x:dp[l][i]){
25             for(int y:dp[i+1][r]){
26                 if( x+y<=5000 ) dp[l][r].insert(x+y);
27                 if( x*y<=5000 ) dp[l][r].insert(x*y);
28             }
29         }
30     }
31 }
32 
33 void init(){
34     memset(ans,-1,sizeof(ans));
35     for(int i=1;i<=11;i++){
36         dfs(1,i);
37         for(int x:dp[1][i]){
38             if( ans[x]==-1 ) ans[x]=i;
39         }
40     }
41 }
42 
43 set<int>num;
44 int main()
45 {
46     init();
47 //  注释掉的部分遍历一下发现前11位就可以到5000了dfs完全可以AC,如果前11位都组不成的数字,以后跟不可能了,因为只有加法和乘法数字只会变大了
48 //    for(int i=1;i<=11;i++){
49 //        for(int x:dp[1][i] ){
50 //            num.insert(x);
51 //        }
52 //    }
53 //
54 //    for( auto &x:num){
55 //        cout<<x<<endl;
56 //    }
57 
58     int T; cin>>T;
59     while( T-- ){
60         int n; cin>>n;
61         cout<<ans[n]<<endl;
62     }
63     return 0;
64 }
原文地址:https://www.cnblogs.com/wsy107316/p/13499286.html