题目大意
将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5; 1,5,1; 5,1,1;
问有多少种不同的分法。
关于解题
求这种寻找分类数目之类的题,很明显的第一时间就会想到用dfs求解,这并不意味着解题方法单一,相反,不同的思路造就了不同的dfs方法,而不同的dfs方法可能又有着巨大的效率差异,这个题目就很好的体现了这一点,我第一次尝试的时候发现效率很低,提交OJ评判也是如此TLE了,于是换了一种思路发现时间复杂度大大减少
TLE的代码(使用一般的套路,易懂但是效率低)
这个就是非常普遍的一个dfs套路,就是搜索所有的情况,再从中筛选出符合条件的,这就导致了效率低下
import java.util.Scanner;
public class Main2676 {
public static Scanner sc = new Scanner(System.in);
public static int n = sc.nextInt(),k = sc.nextInt();
public static int a[] = new int[k+1];
public static int tot=0;
public static void main(String[] args) {
dfs(0,0);
System.out.println(tot);
}
public static void dfs(int ans,int step){
if(ans>n || step>k){
return;
}
if(ans==n&&step==k){
for(int i=1;i<k;i++){
if(a[i]<a[i-1]) return;
}
tot++;
}
for(int i=1;i<=n;i++){
ans+=i;
a[step]=i;
dfs(ans,step+1);
ans-=i;
}
}
}
高效算法(使用了一点技巧)
思路:从小到大进行遍历寻找,寻找k-1个加数就算划分成功(剩下的一个不用查找直接计算即可),为了确保不会重复,寻找的n-1个加数每次不会超过当前的number/cnt,即小于剩下的平均数,如此每次进行dfs搜索效率会非常高
import java.util.Scanner;
public class Main2676 {
public static int ans = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt() , k = sc.nextInt();
dfs(1,k,n);
System.out.println(ans);
}
public static void dfs(int start,int cnt,int num){
if(cnt==1){
ans++;
return;
}
for(int i=start;i<=num/cnt;i++){
dfs(i,cnt-1,num-i);
}
}
}