整数划分 深搜(递归)

java
几个简单的问题,运用深搜(递归)解决
1. N个整数划分为K个子集
2. 在N个整数中选取M个数,使其和等指定值
3. 在N个整数中选取任意个数,使其和等于指定值
4. 在N个整数集合中,将集合划分为两部分,且子集交集为空,使其子集的和尽量相等

import java.util.Arrays;
import com.util.Array;
import com.util.Print;
/**
*2017年12月20日  下午12:44:22<br>
*TODO:<pre><br>  
*   </pre>
    Question:<pre><br>    </pre>
    Analysis:<pre><br>  </pre>
*/
public class 整数划分
{
    public static void main(String[] args)
    {
        // s1_test();
        // s2_test();
        // s3_test();
        s4_test();
    }

    public static void s1_test()
    {
        int i = -1;
        int n = 10;
        while(++i<=n+1)
        {
            System.out.println(n+" "+i+" "+number_split1(n,i));
        }
    }

    /**
     *  TODO:<pre>
     *  N个整数划分为K个子集,每个子集不为空且两两交集为空
     *求,有多少种划分方法
     *考虑一个子集i,如果i单独构成一个子集,那么分法 c(n-1,k-1)
     *如果i不单独构成一个子集,那么k*c(n-1,k)
     *边界条件:
     *( n==k||(n>0&&k==1) ) return 1;
     *( n<k||(n>0&&k==0) ) return 0;
     *  @param n
     *  @param k
     */
    public static int number_split1(int n,int k)
    {
        if( n==k||(n>0&&k==1) ) return 1;
        if( n<k||(n>0&&k==0) ) return 0;
        int sum = 0;
        sum = number_split1(n-1,k-1)+k*number_split1(n-1,k);
        return sum;
    }
    static int arr[];
    static int ans[];
    static int tot;

    public static void s2_test()
    {
        int len = 20,sum = 30,k = 5;
        arr = Array.getRandomIntArrayNoRepeat(1,22,len);
        ans = new int[k+1];
        Arrays.sort(arr);
        tot = 0;
        Print.printArray(arr);
        number_split2(sum,k,len-1);
        System.out.println(tot);
    }

    /**
     *  TODO:<pre>整数划分2
     *  在N个整数中选取M个数,使其和等指定值
     *  分析:
     *  1.递归
     *  先排序,然后对于元素i,我们考虑选取它
     *  然后方程变为d(sum-i,m-1)
     *  不选取:d(sum,m-1)
     *  边界:
     *  sum==0&&m==0  return true
     *  sum<0||m<0,index<0 ||arr[index]>sum return false
     *  @param sum 当前的数字和
     *  @param k 选取K个整数
     *  @param index 数组下标
     */
    public static void number_split2(int sum,int m,int index)
    {
        if( sum==0&&m==0 )
        {
            tot++;
            Print.printArray(ans,1,ans.length-1);
            return;
        }
        if( sum<0||m<0||index<0||arr[index]>sum ) return;
        ans[m] = arr[index];
        number_split2(sum-arr[index],m-1,index-1);
        ans[m] = 0;
        number_split2(sum,m,index-1);
    }

    public static void s3_test()
    {
        int len = 20,sum = 30;
        arr = Array.getRandomIntArrayNoRepeat(1,22,len);
        ans = new int[len];
        Arrays.sort(arr);
        tot = 0;
        Print.printArray(arr);
        number_split3(sum,0,len-1);
        System.out.println(tot);
    }

    /**
     *  TODO:<pre>
     *  整数划分3                     
     *  在N个整数中选取任意个数,使其和等于指定值     
     *  @param sum 和
     *  @param counter 选中的数字个数
     *  @param index 数组当前下标
     */
    public static void number_split3(int sum,int counter,int index)
    {
        if( sum==0 )
        {
            tot++;
            Print.printArray(ans,0,counter-1);
            return;
        }
        if( sum<0||index<0||arr[index]>sum ) return;
        ans[counter] = arr[index];
        number_split3(sum-arr[index],counter+1,index-1);
        ans[counter] = 0;
        number_split3(sum,counter,index-1);
    }
    static int s4M = 2;// s4 阈值

    public static void s4_test()
    {
        int len = 10,sum = 0;
        arr = Array.getRandomIntArrayNoRepeat(1,10,len);
        ans = new int[len];
        Arrays.sort(arr);
        tot = 0;
        Print.printArray(arr);
        for(int i = 0;i<len;i++)
        {
            sum += arr[i];
        }
        number_split4(sum/2,0,len-1);
        System.out.println(tot);
    }

    /**
     *  TODO:<pre>
     *  整数划分4                    
     *  在N个整数集合中,将集合划分为两部分,且子集交集为空,使其子集的和尽量相等
     *  如果和的差超过某个阈值,则输出不能完成信息
     *  分析:
     *  与上面的整数划分类似,将数组求和sum;然后number_split3(sum/2,0,len-1),
     */
    public static void number_split4(int sum,int counter,int index)
    {
        if( sum==0||Math.abs(sum)<=s4M )
        {
            tot++;
            ans[counter] = sum;// 记录 sum相差值,数组最后一位就是差值了
            Print.printArray(ans,0,counter);
        }
        if( index<0 ) return;
        ans[counter] = arr[index];
        number_split4(sum-arr[index],counter+1,index-1);
        ans[counter] = 0;
        number_split4(sum,counter,index-1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值