第12届蓝桥杯 第七题:《砝码称重》的两种解法dfs和dp算法

本文探讨了如何使用闫氏动态规划(DP)和深度优先搜索(DFS)解决《砝码称重》问题。两种方法分别展示了递推求解和暴力搜索策略,针对不同场景优化效率。通过实例代码演示了这两种算法在找到能组成特定重量砝码组合的应用
摘要由CSDN通过智能技术生成

第七题:《砝码称重》

题目大意

在这里插入图片描述

解题思路

思路1:用闫氏dp分析法:

在这里插入图片描述

注意dp[i-1] [j+w[i]] ,这里j+w[i]会产生越界,需要将砝码重量上限100000改成200000;

for (int i =1; i <= n; i++) {
				for (int j = 0; j <= s; j++) {
					//有一个等于j,那么就砝码组成的质量就可以等于j
					dp[i][j] = dp[i-1][j] || dp[i-1][Math.abs(j-w[i])] || dp[i-1][j+w[i]];
				}
			}
思路2:dfs暴力搜索

dfs记住:找重复,找变化,找边界 来写dfs的函数。

预定义一个count数组,来存放0-100000的所有数据。每得到一个大于0的重量sum,就令count[sum] = 1。

最后打印count数组中为1的数,即可。

但是结果会超时,只能拿一半的分数。

private static void dfs(int x,int[] w,int sum,int[] count) {//下一个使用砝码的下标,砝码数组,当前用到砝码的总重量
			if (x == w.length) {
				if (sum > 0) {
					count[sum] = 1;
				}
				return;
			}
			dfs(x+1,w,sum+w[x],count);//加上第x个砝码
			dfs(x+1,w,sum,count);//不加第x个砝码
			dfs(x+1,w,sum-w[x],count);//减去第x个砝码
		} 

完整代码

代码1:用闫氏dp分析法:
import java.util.*;
//背包
public class Main {
	    public static void main(String[] args) {
	    	Scanner scanner = new Scanner(System.in);
	    	int N = 100;
	    	int n = scanner.nextInt();//砝码总数
	    	int[] w = new int[N+1]; //砝码大小
	    	int M = 200000;
	    	int s = 0;//砝码总重量
	    	for (int i = 1; i <= n; i++) {//N个砝码的大小
				w[i] = scanner.nextInt();
				s += w[i];
			}
	    	boolean[][] dp = new boolean[N+1][M+1];//前i个砝码重量是否为j
	    	dp[0][0] = true;
	    	//DP算法
	    	for (int i =1; i <= n; i++) {
				for (int j = 0; j <= s; j++) {
					//有一个等于j,那么就砝码组成的质量就可以等于j
					dp[i][j] = dp[i-1][j] || dp[i-1][Math.abs(j-w[i])] || dp[i-1][j+w[i]];
				}
			}
	    	//用count计数
	    	int count = 0;
	    	for (int j =1 ; j <=s; j++) {
				if (dp[n][j]) {
					count++;
				}
			}
	    	System.out.println(count);
	    }
}
代码2:dfs暴力搜索
import java.util.*;
//dfs暴力
public class Main{
	static int N = 100;//最大砝码数
	static int M = 100000;//最大重量
	static int[] count = new int[M+1];
	    public static void main(String[] args) {
	    	Scanner scanner  = new Scanner(System.in);
	    	 int n = scanner.nextInt();//取的砝码数
	    	 int[] w = new int[n];
	    	for (int i = 0; i < n; i++) {
				w[i] = scanner.nextInt();//砝码的大小
			}
	    	//DFS
	    	dfs(0,w,0);
	    	//遍历count数组
	    	int s = 0;
	    	for (int i = 0; i < count.length; i++) {
				if (count[i] == 1) {
					s++;
				}
			}
	    	//打印结果
	    	System.out.println(s);
	    }
		private static void dfs(int x,int[] w,int sum) {//下一个使用砝码的下标,砝码数组,当前用到砝码的总重量
			// TODO Auto-generated method stub
			if (x == w.length) {
				if (sum > 0) {
					count[sum] = 1;
				}
				return;
			}
			dfs(x+1,w,sum+w[x]);//加上第x个砝码
			dfs(x+1,w,sum);//不加第x个砝码
			dfs(x+1,w,sum-w[x]);//减去第x个砝码
		}    
}
  • 2
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大果壳Clap

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值