买瓜
题目分析
使用dfs依次考虑每一个瓜,我是切开还是不切还是直接不买。这里u表示我当前考虑的瓜,res表示当前获得瓜的总重量,count表示切开瓜的次数。
dfs(u+1,res,count);//不买
dfs(u+1,res+a[u]/2,count+1);//切
dfs(u+1,res+a[u],count);//不切
考虑终点状态就是前n个瓜都遍历完了或者res恰好等于瓜的总重量的一半。
if(res == m){
flag = 1;
min = Math.min(min,count);
}
if(u>n)return;
考虑剪枝,如果当前瓜的切开次数大于等于了我之前记录的最小值,那么就返回。如果当前瓜的重量已经超过了瓜的总重量的一半,那么就返回。还可以考虑什么?如果当前未遍历到的瓜的总重量加到当前已经拥有的总重量上小于瓜的总重量的一半,说明我后面即便全要了也不会使res恰好等于瓜的总重量的一半,那么就返回。
if(res+sum[u]<m||res>m||count >= min){//剪枝
return ;
}
这里的sum[u]就是一个后缀和,表示第u个瓜到第n个瓜的总重量。我们可以在dfs之前预处理出来。
sum = new long[n+1];
for(int i = n-1; i >=0; i --){
sum[i] = sum[i+1]+a[i];
}
最后考虑我们希望尽快的凑齐瓜的总重量的一半,其实可以优先选择重量大的瓜,所以我们可以对瓜的重量进行从大到小的排序。
Arrays.sort(a, new Comparator<Long>() {
@Override
public int compare(Long o1, Long o2) {
return (int) (o2-o1);
}
});
题目代码
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main{
static int n ;
static int m;
static Long []a ;
static long []sum;
static int flag = 0;
static int min = Integer.MAX_VALUE;
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
n = s.nextInt();
m = s.nextInt()*2;
a = new Long [n];
for(int i = 0; i < n; i ++){
a[i] = s.nextLong()*2;
}
Arrays.sort(a, new Comparator<Long>() {
@Override
public int compare(Long o1, Long o2) {
return (int) (o2-o1);
}
});
sum = new long[n+1];
for(int i = n-1; i >=0; i --){
sum[i] = sum[i+1]+a[i];
}
dfs(0,0,0);
if(flag==1)
System.out.println(min);
else
System.out.println(-1);
}
public static void dfs(int u,long res,int count){
//u表示选择过的西瓜数,res表示目前有的重量,count表示切瓜次数
if(res == m){
flag = 1;
min = Math.min(min,count);
}
if(u>n)return;
if(res+sum[u]<m||res>m||count >= min){//剪枝
return ;
}
dfs(u+1,res,count);//不买
dfs(u+1,res+a[u]/2,count+1);//切
dfs(u+1,res+a[u],count);//不切
}
}