洛谷p1025数的划分(正向暴力递归,数学排列与组合问题)

题目链接:https://www.luogu.org/problemnew/show/P1025

 

这是很有价值的一道题,做法也很多,可以搜索可以dp,这里就只讲搜索做法了(dp蒟蒻

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 #include <iomanip>
 5 #include <cstdio>
 6 #include <cstring>
 7 #include <cmath>
 8 using namespace std;
 9 typedef long long ll;
10 typedef unsigned long long ull;
11 const int maxn=1e6+5;
12 int a[maxn];
13 int n,k;
14 int ans;
15 
16 void so(int sum,int step)//组合:序列打乱也算一种
17 {
18     if(step==k)
19     {
20         if(sum==n) ans++;
21         return;
22     }
23 
24     for(int i=1;i<=n;i++)
25     {
26         if(sum+i>n) break;//因为从小到大来的,一个>,后面必定也>,所以可直接跳出!(一个剪枝优化)
27         so(sum+i,step+1);
28     }
29 }
30 
31 void soo(int last,int sum,int step)//排列:打乱仍然算一种,取消重复,使之递增,记录上一个点从它开始!
32 {
33     if(step==k)
34     {
35         if(sum==n) ans++;
36         return;
37     }
38 
39     /*int J=(n-sum)/(k-step);//因为是递增的,所以剩余和/剩余分裂次数=每次的平均数!(不太好想)
40     for(int i=last;i<=J;i++)//如果枚举超过了这个平均数,后面又递增,所以和必定>n,所以到这停即可
41     {                       //以3或5为例跟一遍就明白!
42         soo(i,sum+i,step+1);
43     }*/
44     //或者还写暴力枚举
45     for(int i=last;i<=n;i++)
46     {
47         if(sum+i>n) break;//这个剪枝虽然也不错但没有上面的剪枝优化好...但是好想...
48         soo(i,sum+i,step+1);
49     }
50 }
51 
52 int main()
53 {
54     ios::sync_with_stdio(false); cin.tie(0);
55 
56     cin>>n>>k;
57 
58     soo(1,0,0);
59 
60     cout<<ans<<endl;
61 
62     return 0;
63 }

 

完。

posted @ 2018-10-19 09:18  RedBlack  阅读(288)  评论(0编辑  收藏  举报