• 洛谷 P1025【数的划分】(DFS dp)


    题目链接:P1025 数的划分

    用k个数组成n,且不考虑数的顺序。

    首先我们考虑用搜索的做法,因为数的顺序无关,所以我们采用从小到大的搜索方式,注意有个剪枝

    void dfs(int pre,int step,int sum)
    {
        if (step == k)
        {
            if (sum == n) ans++;
            return;
        }
        for (int i = pre; sum + i*(k - step) <= n; i++)
            dfs(i, step + 1, sum + i);
    }

    这里一定要加sum + i*(k - step) <= n这个剪枝,这句话什么意思呢,就是当前已经确定了step个数了,还剩下k-step个数,sum是当前step个数的和,如果剩下(k-step)都是i的话都不满足总和小于n的话就退出,因为接下来搜索的数必定是大于等于i的,如果剩下(k-step)都是i的话都不满足,那么接下来的搜索也一定不满足,因此退出

    接下来考虑dp的做法,我们

    设F(i,j)为用j个数组成i,答案即为F(7,3)的。

    一个思路是,对于F(7,3)=不含1的方案数+含1的方案数

    首先含1的方案数很好处理,就是前我们用j-1个数去组成i-1,剩下一个数就是1,因此这个方案数等于F(i-1,j-1).

    那么不含1的数的方案呢,不含1的方案说明我们选的方案的j个数每个数都大于1,那我们就让这j个数每个数都减去1,最后这j个数的和是i-j,因此这个方案数就是F(i-j,j),

    这里有些问题,那我们为什么让这j个数每个都减去1呢?为什么不减去2,3,4...呢?因为这个方案是不含1的,选的数是大于等于1的,但不一定大于等于2,3,4...,所以减去1.

    还有疑问,为什么必须选择j个数每个都减去1,而不选择j-1,j-2,或者j-x个数呢,让它们每个都减1。

    如果选择j-x个数那么问题来了,我们到底选择这j个数里的哪j-x个数呢,换句话说,到底哪x个数不减1呢。所以这种去掉x个数的方案不唯一,有多种情况,只有这j个数,每个都去掉1,这是唯一的情况,我们直接加上F(i-j,j)即可,当然这是在i-j>=j的时候。

    所以我们得到了

      F(i,j)=F(i-1,j-1)+F(i-j,j)

     

    #include<bits/stdc++.h>
    using namespace std;
    int n, k;
    int f[205][10];
    int main()
    {
        cin >> n >> k;
        for (int i = 0; i <= n; i++)
        {
            f[i][1] = 1;
            f[i][i] = 1;
        }
        for (int i = 2; i <= n; i++)
        {
            for (int j = 1; j <= k; j++)
            {
                f[i][j] = f[i - 1][j - 1];
                if (i - j >= j)
                    f[i][j] += f[i - j][j];
            }
        }
        cout << f[n][k] << endl;
        return 0;
    }

     

     

  • 相关阅读:
    删除:恶意主页
    Winuser.h
    安天磁盘免疫工具研究的初步解答
    C#读写XML文件
    阻止系统关机
    在WebBrowser中屏蔽对话框
    如何用正确的方法写出高质量软件的75条体会
    怪事~
    GRUB4DOS中文自述文档;Grub4dos中文ReadMe
    开始菜单变成的经典样式,XPsuaa样式丢失
  • 原文地址:https://www.cnblogs.com/xiaoguapi/p/10480375.html
Copyright © 2020-2023  润新知