P1025 [NOIP2001 提高组] 数的划分

这篇博客主要探讨了NOIP2001提高组的一道数的划分问题,强调了在解决此类问题时分法顺序的自由性和剪枝策略的重要性。作者通过dfs深度优先搜索算法,并使用变量l、n1、k1来跟踪递归状态,实现了一个高效的解决方案。博客还讨论了在剪枝过程中,取平均值作为最大值的最优解,并分析了两种剪枝边界条件的影响。最后,给出了AC代码供读者参考。
摘要由CSDN通过智能技术生成

题目链接:[NOIP2001 提高组] 数的划分 - 洛谷

这题一定要注意: 分法顺序是自由安排的, 答案输出一个分法就行了...因为没注意到这个条件想的焦头烂额...

dfs剪枝, 用l存上一层递归是什么数字(使得每进一次递归数字只能更大), 用n1存还剩下多少的数字可以分, 最后再用k1存这是第几层递归   当进行到k-1次递归的时候(即k==1), 最后一个数字必定是n-n1, 因此可以return此次递归

void dfs(ll l,ll n1,ll k1)
{
    if(k1==1)//当此次递归到了第k次的时候, 此次递归会退出, 最后一个数字取最大值
    {
        ans++;
        return;
    }

    for(ll i=l;i<=n1/k1;i++)
        dfs(i,n1-i,k1-1);
}

关于剪枝:

for(ll i=l;i<=n1/2;i++)
    dfs(i,n1-i,k1-1);

此处i<=n1/k1或者i<=n1/2都是可以的

因为题目要求将整数 n 分成 k 份, 所以最大值取剩下的数字取平均值是最优解

而n1/2显然是大于等于n1/k1的, 但当枚举到本该到不了这么大的数字的时候, 在下一层循环会因为 l 比限制的条件n1/2更大而进不去递归, 对答案不会有影响, 但时间复杂度会更高一些

ac代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <stack>
#include <deque>
#include <map>
#include <set>
using namespace std;
#define ll long long
#define endl "\n"
#define rep(i, a, b) for (ll i = (a); i <= (b); i++)
#define repr(i, a, b) for (ll i = (a); i < (b); i++)
#define rrep(i, a, b) for (ll i = (b); i >= (a); i--)
#define rrepr(i, a, b) for (ll i = (b); i > (a); i--)
#define min(a,b) (a)<(b)?(a):(b)
#define max(a,b) (a)>(b)?(a):(b)

ll cnt,n,m,t,ans,ant,k;
const int N=1e5+10;
ll arr[20][N];
string str;

inline ll read()
{
    char c = getchar();int x = 0,s = 1;
    while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();}//是符号
    while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();}//是数字
    return x*s;
}

void dfs(ll l,ll n1,ll k1)
{
    if(k1==1)//当此次递归到了第k次的时候, 此次递归会退出, 最后一个数字取最大值
    {
        ans++;
        return;
    }

    for(ll i=l;i<=n1/k1;i++)
        dfs(i,n1-i,k1-1);
}

void solve()
{
    n=read();
    k=read();
    dfs(1,n,k);
    cout<<ans;
    return;
}

int main()
{
    solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值