• 洛谷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
    ");  //剪枝1 
    24         return 0;
    25     }
    26     else{
    27         dfs(0,0,0);
    28         if(ans==2147483647)printf("-1
    ");
    29         else printf("%d
    ",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 }
  • 相关阅读:
    百度云管家开机启动如何取消
    双语小说阅读:《谁动了我的奶酪》
    [Swift]方法
    Swift中的类型属性(静态变量)
    Swift 学习之二十一:?和 !(详解)
    苹果Swift可为Windows/Android开发软件了
    iOS7下滑动返回与ScrollView共存二三事
    swift c++ oc 混编
    RTOS
    STM32 RTC
  • 原文地址:https://www.cnblogs.com/running-coder-wfh/p/11163527.html
Copyright © 2020-2023  润新知