题目链接:https://www.dotcpp.com/oj/problem2354.html
体会:尝试了具有返回值dfs()函数的设计,以及强化了搜索问题的可行性、最优性的理解
import java.util.*;public class Test{public static int[] arr;public static int cnt = 0; //记录长度<=50的小木棍数量public static int sum = 0; //记录所有长度<=50的小木棍的长度之和public static boolean[] visited; //标记小木棍的使用状态public static boolean dfs(int targetCount, int nowCount, int nowSum, int len, int index){//targetCount: 需要拼凑的木棍数量//nowCount: 目前已经拼凑的数量//nowSum: 当前由若干小木棍拼凑的长度//len: 此次枚举的木棍长度//index: 遍历的下标if(nowCount == targetCount){ //所有小木棍恰好能拼凑出 targetCount根长度为len的木棍return true;}if(nowSum == len){ //已经拼凑出一根长度为len的木棍,接着往下尝试return dfs(targetCount, nowCount + 1, 0, len, cnt);}for(int i = index; i >= 0; i--){if(!visited[i] && nowSum + arr[i] <= len){ //剪枝2:保证小木棍拼凑的长度 <= lenvisited[i] = true;if(dfs(targetCount, nowCount, nowSum + arr[i], len, i-1)){ //此处记得将dfs()的结果returnreturn true;}visited[i] = false;//剪枝3:如果当前arr[i]尝试失败后(因为只有失败后才回溯到此处),证明arr[i]对当前的结果无作用,直接跳过while(i > 0 && arr[i] == arr[i-1]) i--;}}return false;}public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();arr = new int[n+1];visited = new boolean[n+1];int num;for(int i = 1; i <= n; i++){num = sc.nextInt();if(num <= 50){ //长度>50的小木棍全都抛弃,不然AC不了arr[++cnt] = num;sum += num;}}//按从小到大排序,然后逆序遍历Arrays.sort(arr, 1, cnt + 1);//枚举切割前木棍的长度,其范围为[最长的小木棍长度,所有小木棍长度之和]//注意这里说的小木棍都是指长度<=50的for(int len = arr[cnt]; len <= sum; len++){//剪枝1:sum必须能整除木棍的长度if(sum % len == 0){Arrays.fill(visited, false);//切割前木棍的数量int k = sum / len;//我们需要去利用现有的小木棍,使其能刚好拼凑出k根长度为len的木棍//如果当前的方案能够生效,必然是最小的长度if(dfs(k, 0, 0, len, cnt)){System.out.println(len);return;}}}}}
