洛谷T1874 快速求和

本题思路非常明确:在所有能插入加号的位置枚举加号是否存在,对于每一种情况,若求得和为n则更新答案。

但是看看数据规模。。。长度<=40,也就是说枚举的时间最多可达2^39,显然会T,所以需要剪枝。

剪枝1:若整串拆分为单个数字后求和,所得结果>n,则一定无解。

原因显然在一次拆分后,新生成的数字的和不会比未拆分之前的大(不要问我为什么,这是直觉)。

那么对于某个串,它对应的和最小的拆分方案即为:将其拆分为单个数字。

于是乎,整串对应的最小的和都>n,那么就不可能有可行解了。

剪枝2:若将未处理部分作为一个数字与已处理部分相加,所得的和<n,则在此递归子树中一定无解。

原因:类比一下剪枝1,可得:对于某个串,它对应的和最大的拆分方案为:直接将其转化为数字,即不拆分(不要问我为什么,这也是直觉)。

那么,将未处理部分作为一个数字与已处理部分相加,就是此递归子树中对应和最大的方案。

如果最大的和都<n,那么就不可能有可行解了。

剪枝3:若当前加号数量>=ans,则此递归子树中无更优解。这一点十分显然。

剪枝4:若将未处理部分拆分为单个数字后与已处理部分求和,所得的和>n,则在此递归子树中一定无解。

原因:同剪枝1。

剪枝5:若找到一个可行解,则此递归子树中无更优解。再搜下去,加号会增多,一定得不到比此可行解更优的解。

实现细节及剪枝位置详见代码及注释。

 1 #include<cstdio>
 2 #include<cstring>
 3 
 4 using namespace std;
 5 
 6 void dfs(int,int,int);
 7 inline int val(int,int);  //将某子串转化为数字 
 8 inline int min(int,int);
 9 inline int qh(int,int);  //将某子串拆分为单个数字后求和 
10 
11 char s[50];
12 int a[50],l,ans=2147483647,sum=0,n;
13 
14 int main(){
15     scanf("%s",s+1);
16     scanf("%d",&n);
17     l=strlen(s+1);
18     for(int i=1;i<=l;i++){
19         a[i]=s[i]-'0';
20         sum+=a[i];
21     }
22     if(sum>n){
23         printf("-1\n");  //剪枝1 
24         return 0;
25     }
26     else{
27         dfs(0,0,0);
28         if(ans==2147483647)printf("-1\n");
29         else printf("%d\n",ans);
30     }
31 
32     return 0;
33 }
34 
35 void dfs(int res,int p,int dep){  //res:已处理部分的和 p:标记已经处理到何处 dep:加号数量 
36     int temp=res+val(p+1,l);  //将未处理部分作为一个数字与已处理部分相加
37     if(temp<n)return;  //剪枝2 
38     if(dep>=ans)return;  //剪枝3 
39     if(res+qh(p+1,l)>n)return;  //剪枝4 
40     if(temp==n){  //找到可行解 
41         ans=min(ans,dep);  //更新答案 
42         return;  //剪枝5 
43     }
44     for(int i=p+1;i<l;i++){
45         temp=res+val(p+1,i);
46         dfs(temp,i,dep+1);
47     }
48 }
49 
50 inline int val(int l,int r){
51     int ans=0;
52     for(int i=l;i<=r;i++)ans=(ans<<3)+(ans<<1)+a[i];
53     return ans;
54 }
55 
56 inline int min(int x,int y){
57     if(x<y)return x;else return y;
58 }
59 
60 inline int qh(int l,int r){
61     int ans=0;
62     for(int i=l;i<=r;i++)ans+=a[i];
63     return ans;
64 }

转载于:https://www.cnblogs.com/running-coder-wfh/p/11163527.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值