洛谷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 }
完。