• 数的划分(深搜剪枝+题解)


                                                               数的划分

    解题思路 

           本题的意思是将一个数n化解为k份,有几种不同的方案。例如k=3的时候,a+b+c=n,求a、b、c有几种不同的取值。为了避免出现重复,搜索的时候按照从大到小搜索。依次枚举a、b、c的值进行判断。

           直接搜程序的运行速度是特别慢的,需要控制好搜索的上下界。

    约数条件:

          (1)由于我们是按照从小到大搜索的,所以扩展节点的下界,不能小于前一个扩展节点的值。

               (意思是搜索下个值,一定大于等于当前值)

          (2)接下来考虑上界,看图吧

                  

              将21分为6份,当搜索到a[i]的时候(也就搜索到5的时候),判断搜索上下界,显然搜索的上界是a[i-1](也就是4,            因为我们是按照递增的顺序进行搜索的)

              接下来判断下界,a[i] (a[i]=5)这个数肯定比n(n=21)小,但是用n作为下界,有大的区间完全没用,那怎么才              能比5稍微大一点点呢?那就是求取没被搜索到的数的平均数,如果将已经搜到的数加起来:

              设定m=6表示总共要分6份,n = n - a[1] + ... + a[i-1];(表示还有多大的值没被搜索出来,就是5+6的值)

              当搜索到4的时候,是搜到了第四个数,k = 4;

              后边的平均数就等于n/(m-k+1);

              后边的数取平均数,肯定是大于等于a[i]的。

              控制好上下界,这道题就解决了。

    例题地址:https://loj.ac/problem/10018

    AC代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    int n,m,sum = 0;
    int a[10];
    
    void dfs(int k)
    {
        if(n == 0)
            return;
        if(k == m){
            if(n >= a[k])//最后一个数,只要保证大于等于前一个数,就可以
                sum++;
            return;
        }
        for(int i = a[k];i <= n/(m-k+1);i++){//设定搜索的上下界,剪枝的一种
            a[k+1] = i;
            n -= i;
            dfs(k+1);
            n += i;
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        a[1] = 1;
        dfs(1);
        printf("%d
    ",sum);
        return 0;
    }
    

    我走的很慢,但我从不后退。                                         

    ——林肯 

  • 相关阅读:
    POJ 2411 Mondriaan's Dream
    POJ 2505 A multiplication game
    HDOJ(HDU) 3949 XOR
    雅礼集训DAY 6 T1 xmasdag
    bzoj 2159: Crash 的文明世界
    如何查看Ubuntu版本
    Ubuntu如何安装谷歌Chrome浏览器
    使用nano编辑器进行查找和替换
    Ubuntu修改用户和root密码
    Anaconda/Conda创建环境时报错的解决方案
  • 原文地址:https://www.cnblogs.com/codepeanut/p/12920498.html
Copyright © 2020-2023  润新知