经典dfs剪枝问题-木棒

这篇文章主要介绍了如何使用Java编程实现一个递归函数,结合动态规划策略,解决给定一组木棒长度的问题,寻找可以组合成总长度等于给定目标值的最小木棒数量。
摘要由CSDN通过智能技术生成

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * @Author congge
 * @Date 2024/3/14 22:05
 * @description https://www.acwing.com/problem/content/169/
 */
public class Main {
    static FastReader sc = new FastReader();
    static PrintWriter out = new PrintWriter(System.out);
    static int N = 70;
    static int n,sum,len;
    static int[] a = new int[N];
    static boolean[] st = new boolean[N];

    public static boolean dfs(int u,int cur,int start){
        if (u * len == sum) return true;

        //这里不是直接调用dfs(u + 1,0,0),而是区凑下一根木棒,要把所有木板一直凑到u * len == sum
        //并且每一根都得凑成功
        if (cur == len) return dfs(u + 1,0,0);

        //从编号为start的木板开始凑,防止出现冗余答案
        for(int i = start;i < n;i++){
            if (st[i]) continue;    //用过的木棒不能用

            if (a[i] + cur <= len){
                //这种情况是满足条件的,继续凑
                st[i] = true;
                //往下凑,看看能不能凑到
                if (dfs(u,cur + a[i],i + 1)) return true;
                //如果凑到了就算是一个答案,没凑到就恢复现场
                st[i] = false;
            }

            //这里是没凑到的情况
            //如果是第一个木棒放进去凑不了,那么以后一定会出现要把该木棒放在其他木棒的第一个位置
            //同理,其他位置也容不下第一个木棒,那么以a[i]作为第一个木棒的答案都返回失败
            if (cur == 0)return false;

            //最后一个木板虽然匹配上了,但是后面的木棒凑不起来
            //因为是从大到校枚举,4 后面可以是 2 + 2
            //虽然4满足题意,2 + 2也满足题意
            //如果把2 + 2放在这里,那么后面的4如果遇上两根木棒都剩下2就凑满的情况,就匹配不上了
            if (a[i] + cur == len) return false;

            //如果是中间没匹配上,那没关系,后面还有选择的机会
            //就比如做一件事,第一步就错了,后面就没必要继续了
            //最后一步对了,但是其他事干不成了,那么也不用去做其他事了

            //但是中间错了,还有其他补救机会

            //第a[i]数放进去没用,那么与a[i]相等的数就不用再判断了
            int j = i + 1;
            while (j < n && a[j] == a[i]) j++;
            i = j - 1;
        }
        return false;
    }

    public static void main(String[] args) {
        while (true){
            n = sc.nextInt();
            if (n == 0) break;
            sum = len = 0;
            for(int i = 0;i < n;i++){
                a[i] = sc.nextInt();
                sum += a[i];
                len = Math.max(len,a[i]);
            }
            Arrays.sort(a,0,n);
            for(int i = 0,j = n - 1;i < j;i++,j--){
                int temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
            while (true){
                if (sum % len == 0 && dfs(0,0,0)){
                    out.println(len);
                    break;
                }
                len++;
            }
            Arrays.fill(st,0,n,false);
        }
        out.flush();
    }
}

class FastReader {
    StringTokenizer st;
    BufferedReader br;

    FastReader() {
        br = new BufferedReader(new InputStreamReader(System.in));
    }

    String next() {
        while (st == null || !st.hasMoreElements()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return st.nextToken();
    }

    int nextInt() {
        return Integer.parseInt(next());
    }

    String nextLine() {
        String s = "";
        try {
            s = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return s;
    }

    long nextLong() {
        return Long.parseLong(next());
    }

    double nextDouble() {
        return Double.parseDouble(next());
    }

    // 是否由下一个
    boolean hasNext() {
        while (st == null || !st.hasMoreTokens()) {
            try {
                String line = br.readLine();
                if (line == null)
                    return false;
                st = new StringTokenizer(line);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return true;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DFS深度优先搜索)是一种常见的图遍历算法,它使用递归或栈的方式,从一个顶点出发,沿着一条路径一直到达最深的节点,然后回溯到上一层继续遍历其他节点。DFS常被用于解决图的连通性问题、路径问题等。在实际应用中,可以使用DFS进行状态搜索、图的遍历、拓扑排序等。 剪枝是指在搜索过程中,通过一系列的策略判断,提前终止当前搜索分支,并跳过一些无用的搜索路径,从而减少搜索时间。剪枝的核心在于提前排除某些明显不符合条件的状态,以减少无效搜索的时间开销,提高效率。在算法设计中,剪枝通常会利用一些特定的性质或条件进行判断,从而缩小搜索空间。 动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划通常用于求解最优化问题,它通过定义状态和状态转移方程,采用自底向上的思路,逐步求解每个子问题的最优值,最终得到原问题的最优解。动态规划的核心是存储已经计算过的子问题的解,避免了重复计算。 贪心算法是一种基于局部最优解的策略,它通过每一步选择在当前状态下最优的解,以期望得到全局最优解。贪心算法的基本思想是由局部最优解推导出全局最优解,通常通过贪心选择性质、最优子结构和贪心选择构成三部分。贪心算法相比其他算法,如动态规划,它的优势在于简单、高效,但缺点在于不能保证获取到全局最优解,只能得到一个近似解。 综上所述,DFS剪枝、动态规划和贪心算法算法设计和问题求解中都发挥着重要的作用。具体使用哪种算法取决于问题的性质和要求,需要在实际应用中进行综合考虑和选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值