洛谷 P1025 数的划分

https://www.luogu.org/problemnew/show/P1025

本题有两种解法 dfs和dp

dfs

dfs很好理解 只是需要加上一个剪枝:

sums+i*(k-t)<=n

其实这个也是很容易理解的 因为我们为了避免重复 将循环从小到大进行 那么如果sums+i*(k-t)>n,说明后面的数肯定不满足条件

#include<bits/stdc++.h>

using namespace std;
int n,k,anss,sums;

void dfs(int now,int t)
{
    if(t==k)
    {
        if(sums==n)
        anss++;
        return;
    }
    for(int i=now;sums+i*(k-t)<=n;i++)
    {
        sums+=i;
        dfs(i,t+1);
        sums-=i;
    }
}

int main()
{
    cin>>n>>k;
    dfs(1,0);
    cout<<anss<<endl;
}

也可以把sums当作参数传进去:

#include<bits/stdc++.h>

using namespace std;
int n,k,anss;

void dfs(int now,int t,int sums)
{
    if(t==k)
    {
        if(sums==n)
        anss++;
        return;
    }
    for(int i=now;sums+i*(k-t)<=n;i++)
    dfs(i,t+1,sums+i);
}

int main()
{
    cin>>n>>k;
    dfs(1,0,0);
    cout<<anss<<endl;
}

dp

这个不是很好想 我是抄的题解:

f[i][x] 表示 i 分成 x 个非空的数的方案数。

显然 i<x 时 f[i][x]=0 , i=x 时 f[i][x]=1;

其余的状态,我们分情况讨论:

①有1的 ②没有1的

第一种情况,方案数为 f[i-1][x-1]

第二种情况,方案数为 f[i-x][x] (此时 i 必须大于 x)

所以,状态转移方程为: f[i][x]=f[i-1][x-1]+f[i-x][x]

解释一下:

一个数字i被分成K份时,存在两种情况,一个是有一存在,如6分成三份的1 2 3;另一种是没有一存在,比如6分成三份的2 2 2;
如果有1存在,还是用6分三份举例,那么就是对5进行分两份的操作,再加上那个1;如果没有1存在,我们先将6变成(1+a)+(1+b)+(1+c);那么a+b+c=6-3=3;然后他们需要被分配到三个位置上从而防止1的出现——即【i-k】【k】

#include<bits/stdc++.h>

using namespace std;
long long int n,k,a[205][10],i,j;
int main()
{

    cin>>n>>k;
    for(i=1;i<=n;i++)
    {
        a[i][1]=1;
        a[i][0]=1;
    }
    for(i=2;i<=k;i++)
    {
        a[1][i]=0;
        a[0][i]=0;
    }
    for(i=2;i<=n;i++)
    for(j=2;j<=k;j++)
    {
        if(i>j)
        a[i][j]=a[i-1][j-1]+a[i-j][j];
        else
        a[i][j]=a[i-1][j-1];
    }
    cout<<a[n][k];
 } 
原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/10953003.html