洛谷 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;
}

 

 

 

posted @ 2019-03-05 22:47  TLE自动机  阅读(328)  评论(0编辑  收藏  举报