AcWing_165. 小猫爬山 (算法日记)

本题心路历程

(错解)拿到题目,以为很简单,想直接暴力搜,以体重数组为宽度,以小猫数量为深度,设定book数组记录,如果这个小猫被放进车里,记录1,那下一次跳过遍历,每一次搜索整个数组,如果把小猫放入不超载就放,一直到遍历到数组尾部,加一辆车;

便有了下面的错误代码。

package dfs;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;



public class 小猫下山 {
	static int w;
	static int cnt;
	static int n;
	static int num=0;
	static int sum;
	static Integer[] a=new Integer[18];
	static int book[]=new int [18];
	static int flag=0;
 public static void main(String[] args) {
	Scanner sc=new Scanner(System.in);
	 n=sc.nextInt();
	 w=sc.nextInt();
	 for(int i=0;i<n;i++)
	 {
		 a[i]=sc.nextInt();
	 }

	 Arrays.sort(a,0,n-1,new Comparator<Integer>() {

		@Override
		public int compare(Integer o1, Integer o2) {
			// TODO Auto-generated method stub
			return o2-o1;
		}
	}) ;
	 
	 dfs(1);
	 System.out.println(cnt);
	 sc.close();
}//应该排个序,先排小的,最后排大的
 //cur现在小猫的个数
 //sum现在小猫的重量
 //m 记录n
 //版本1,能加就加,
 static boolean dfs(int cur)
 {
	 if(num>=n) return true;

	 if(flag==1)  {cnt++; //System.out.println(cur+"#"+num+"@"+sum+"%%");
	 num=num+cur-1;sum=0;flag=0;return dfs(1);}
	
	 for(int i=0;i<n;i++)
	 {
		 if(i==n-1) {flag=1; }//这个flag一定要放在最上面,标记数组最后一只小猫
		
		 if(sum+a[i]>w) continue;
		 if(book[i]==1) continue;
		 //if(i==n-1) flag=1;  错误的位置 应该写在上面,不然最后一个小猫体重大,就不会执行这行语句
		 sum+=a[i];//能装则装
		//  System.out.println(sum+"**");
		 book[i]=1;
		
		 dfs(cur+1);
		 if(num>=n) return true;//很关键,我找到答案,后面都不用回溯了
		  book[i]=0;
		  int t=sum;
		 sum-=a[i];
		// System.out.println(t+"-"+a[i]+"="+sum);  测试用 忽略就好
		
	 }
	 if(flag==1)  {cnt++; //System.out.println(cur+"#"+num+"@"+sum+"%%");//测试
	 num=num+cur-1;sum=0;flag=0;return dfs(1);}//在最后加一个判断,接住i=N-1的情况,防止最后一个是数太大直接continue进不去递归了
	return false;
	 
 }
}

前面案例都能过,直到我遇到了这样一组案例

6.。。。。。。

错误原因,没有枚举到所有情况,局部最优不等于全局最优。。。。

所以,请看方案二

可以直接把重量大的小猫放到新的车里,那么每拿到一只小猫,我们可以把它放到前cnt辆车里,或者新开一辆车。

直到达到递归边界,与之前记录的情况求个最小值,这样就能遍历到所有的情况。

ac代码。

package dfs;

	import java.util.Arrays;
	import java.util.Comparator;
	import java.util.Scanner;
public class 小猫下山修正 {

		static int w;
		static int ans=10000000;
		static int n;
		//static int num=0;
		//static int sum;
		static Integer[] cat=new Integer[19];
		//static int book[]=new int [18];
		//static int flag=0;
		static int cab[]=new int [100];
		//static int cat[]=new int [100];
	 public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		 n=sc.nextInt();
		 w=sc.nextInt();
		 for(int i=1;i<=n;i++)
		 {
			 cat[i]=sc.nextInt();
		 }
		
		 //排个序,先放大的,减少搜索次数
		 Arrays.sort(cat,1,n+1,new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				// TODO Auto-generated method stub
				return o2-o1;
			}
		}) ;
		 
		 dfs(1,0);
		 System.out.println(ans);
		 sc.close();
	}//应该排个序,先排小的,最后排大的
	 //cur现在小猫的个数
	 //cnt 现在车的数目

	
	
	 //版本2 枚举情况最后求min
	 static void dfs(int cur,int cnt)
	 {
		 if(cnt>=ans) return ;//剪枝
	     if(cur==n+1) {ans=Math.min(cnt,ans);return;}//达到递归边界,就更新
	     //每拿到一直小猫,先往已有的cnt量车里比对,装不下就新开一辆车
		 for(int i=1;i<=cnt;i++)
		 {
           if(cab[i]+cat[cur]>w) continue;//剪枝,如果超重就跳过这个小猫
           cab[i]+=cat[cur];//把当前小猫放到车里
           dfs(cur+1,cnt);//这个地方容易越界?
           cab[i]-=cat[cur];//回溯
	 }
		 //能来到这里,说明前面没有找到小猫的位置
		 cab[cnt+1]=cat[cur];
		 dfs(cur+1,cnt+1);
		 cab[cnt+1]=0;//回溯
	}
}


  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值