这题一定要注意: 分法顺序是自由安排的, 答案输出一个分法就行了...因为没注意到这个条件想的焦头烂额...
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;
}