芙芙镇楼~
这俩题一样,不过acwing上的是多组数据,洛谷上只有一组(但是数据很强)
这是acwing的题面
167. 木棒
乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过 50 个长度单位。
然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。
请你设计一个程序,帮助乔治计算木棒的可能最小长度。
每一节木棍的长度都用大于零的整数表示。
输入格式
输入包含多组数据,每组数据包括两行。
第一行是一个不超过 64 的整数,表示砍断之后共有多少节木棍。
第二行是截断以后,所得到的各节木棍的长度。
在最后一组数据之后,是一个零。
输出格式
为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。
数据范围
数据保证每一节木棍的长度均不大于 50。
输入样例:
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
输出样例:
6
5
这是洛谷的题面
题目描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 50。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入格式
第一行是一个整数 n,表示小木棍的个数。
第二行有 n 个整数,表示各个木棍的长度 ai。
输出格式
输出一行一个整数表示答案。
输入输出样例
输入 #1复制
9 5 2 1 5 2 1 5 2 1
输出 #1复制
6
说明/提示
对于全部测试点,1≤n≤65,1≤ai≤50。
下面是分析讲解
本题 想要暴力搜索可要好好想想剪枝的过程。因为测试数据还是很多的,而且我们要确定一个最小的,符合题意的长度。就意味着我们要从小到大枚举长度len,对于每一个len,我们都要进行一通搜索,直到找到第一个符合题意的len,退出,所以运行复杂度可以想见,我们要进行重重剪枝。
下面是剪枝的想法
1.
按从大到小排序//剪枝 先搜情况少的,这个搜索树的宽度就小,因为长的木棍可选择的情况少
2.如果i木棍失败了 ,后面遇到了与i等长的j木棍,则 直接判定失败
3.如果第一根就失败了,那么直接判定此情况失败、(反证法,如果这一根在第一个的位置判定失败,它被放在了后面的位置,则可以把它平移到第一个的位置上,则矛盾。中间的木棍就不一样了,可能因为恰好那一个组合不合理,换一种组合方案就成功了)
4.同理,最后一个失败,则也失败
5.在枚举的时候,正确答案一定是总长的因子
总之,看代码叭~
package dfs;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class 木棒多组数值 {
//思路 按从大到小排序//剪枝 先搜情况少的、
//如果i木棍失败了 ,后面遇到了与i等长的j木棍,则 直接判定失败
//如果第一根就失败了,那么直接判定此情况失败、//同理,最后一个失败,则也失败
static Integer a[]=new Integer [70];
static int len;
static int n;
static int num;
static int sum;
static int book[]=new int [70];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while(sc.hasNext())
{
num=0;
sum=0;len=0;
for(int j=0;j<70;j++)
{
if(book[j]!=0) book[j]=0;
}
n=sc.nextInt();
if(n==0) break;
int max=0;
for(int i=1;i<=n;i++)
{
a[i]=sc.nextInt();
sum+=a[i];
max=Math.max(max, a[i]);
}//剪枝 先对可选择情况少的(大木棍)进行拼接
Arrays.sort(a,1,n,new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
return o2-o1;
}
});
for( len=max;len<sum;len++)
{
if(sum%len!=0) continue;//剪枝 因为符合题意的长度一定是sum的因子
num=sum/len;//当前长度下的拼接好的木棍个数
if(dfs(1,0,1)) break;
}
System.out.println(len);
}
}
//cnt 现在正在处理的木棒
//cur 现在的木棒长度
//x 当前正在拼的木棍的第一个可用的编号//为了保证木棍组成木棒的编号 是递减的,避免重复
static boolean dfs(int cnt,int cur,int x)
{
// System.out.println(cnt);
if(cnt>=num) return true;
if(cur==len) return dfs(cnt+1,0,1);
//剪枝 记录已经失败的木棍的长度
int fail=0;
for(int i=x;i<=n;i++)
{
if(book[i]==0&&cur+a[i]<=len&&a[i]!=fail)
{
book[i]=1;//记录使用这个棍
if( dfs(cnt,cur+a[i],i+1)) return true;//能放,就直接走了
book[i]=0;
fail=a[i];//记录失败的木棍
if(cur==0||cur+a[i]==len) return false;
}//剪枝 如果是第一个就失败或者最后一个失败,该情况一定不符,直接排除
}
return false;
}
}
package dfs;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class 小木棍 {
//改bug思考,仔细想一下为啥不去等1234的数据会过不去呢???//明白了x每次从1开始,第0个读取不到
//思路 按从大到小排序//剪枝 先搜情况少的、
//如果i木棍失败了 ,后面遇到了与i等长的j木棍,则 直接判定失败
//如果第一根就失败了,那么直接判定此情况失败、//同理,最后一个失败,则也失败
static Integer a[]=new Integer [70];
static int len;
static int n;
static int num;
static int sum;
static int book[]=new int [70];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
int max=0;
for(int i=1;i<=n;i++)//之前从0开始读n不带等,会数组越界
{
a[i]=sc.nextInt();
sum+=a[i];
max=Math.max(max, a[i]);
}//剪枝 先对可选择情况少的(大木棍)进行拼接
Arrays.sort(a,1,n,new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
return o2-o1;
}
});
for( len=max;len<=sum;len++)
{
if(sum%len!=0) continue;//剪枝 因为符合题意的长度一定是sum的因子
num=sum/len;//当前长度下的拼接好的木棍个数
if(dfs(1,0,1)) break;
}
System.out.println(len);
}
//cnt 现在正在处理的木棒
//cur 现在的木棒长度
//x 当前正在拼的木棍的第一个可用的编号//为了保证木棍组成木棒的编号 是递减的,避免重复
static boolean dfs(int cnt,int cur,int x)
{
//System.out.println(cnt+" "+cur);
if(cnt>=num) return true;
if(cur==len) return dfs(cnt+1,0,1);
//剪枝 记录已经失败的木棍的长度
int fail=0;
for(int i=x;i<=n;i++)//这个地方一定要有等号,不然会遍历不全
{
if(book[i]==0&&cur+a[i]<=len&&a[i]!=fail)
{
book[i]=1;//记录使用这个棍
if( dfs(cnt,cur+a[i],i+1)) return true;//能放,就直接走了
book[i]=0;
fail=a[i];//记录失败的木棍
if(cur==0||cur+a[i]==len) return false;
}//剪枝 如果是第一个就失败或者最后一个失败,该情况一定不符,直接排除
}
return false;
}
}
不过要注意的是,这个代码并不能通过洛谷的全部数据(超时){java太慢了?} 博主后期还会进一步优化哒~