腾讯笔试:小Q穿越怪兽谷问题

题目描述

小Q打算穿越怪兽谷。他不会打怪,但是他有钱(笑~*´∀`)。他知道,只要给怪兽一定的金币,怪兽就会一直护送着他出谷。
在谷中,他会依次遇见N之怪兽,每只怪兽都有自己的武力值和要“贿赂”它所需的金币数。如果小Q没有“贿赂”某只怪兽,而这只怪兽“武力值”又大于护送他的怪兽武力值之和,这只怪兽就会攻击他。
小Q想知道,想要成功穿越怪兽谷而不被攻击,他最少要准备多少金币。

输入描述

第一行输入一个整数N,代表怪兽的只数
第二行输入N个整数d1,d2,…,dn,代表武力值
第三行输入N个整数p1,p2,…,pn,代表收买N只怪兽所需的金币数
(1≤N≤50,1≤d1,d2,…,dn≤1012,1≤p1,p2,…,pn≤2)

输出描述

输出一个整数,代表所需的最小金币数

示例1

输入
3
8 5 10
1 1 2
输出
2

示例2

输入
4
1 2 4 8
1 2 1 2
输出
6

题目分析

这道题读完,我的第一反应是,真简单,不就是设置一个变量nowD,记录小Q当前的武力值之和,然后进行N次循环,依次遭遇怪兽。每遇到一个怪兽判断一下,当前的武力值之和nowD是否小于碰到怪兽的武力值,如果小于则花钱贿赂,否则直接通过。最后输出总共花费的金币数。
结果当然是我太傻太天真,作为鹅厂的算法题,怎么可能这么简单。
对于示例2而言,由于从头到尾,nowD都会小于怪兽的武力值,所以每次都需要购买,通过上面做法,结果输出正确。但是对于示例1而言,当遭遇第2个怪兽时,按上面做法,由于nowD为8大于怪兽武力值5,所以选择不贿赂,但遭遇第3个怪兽时,则必须贿赂通过,则输出结果为1+2=3,并不是示例1输出的答案2。示例1正确的走法是,贿赂第一和第二个怪兽,碰到第三个怪兽nowD=13大于10,成功出谷,输出2。

不想听我罗嗦,想直接看做法请看下面

解法

采用递归的方法解决。
由于每次遇到怪兽,先不论打不打过,都有两种选择,贿赂与不贿赂,即会导致出现两种路线。于是通过递归调用,生成2N-1条路线。一次递归方法中,分别计算贿赂与不贿赂这两条路线的花费金币数,比较后返回花费最少的路线所需的金币数。由于此方法类似于穷举算法,为了减少计算量,走到某一步时,若怪兽武力值大于nowP时,直接截断返回整数的最大值Integer.MAX_VALUE,这样可以便于比较输出最小值。最后递归的结束条件是,当走过最后一直怪兽时返回最终的花费。
语言表达能力有限,觉得听不懂的小伙伴可以看下图或者直接看代码。

解法示例图

以示例1为例
在这里插入图片描述

示例代码(java)

import java.util.Scanner;

public class Main{
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();//挂
		long[] D = new long[N];//怪兽武力值数组
		int[] P = new int[N];//怪兽贿赂所需金币数组
		//循环录入
		for(int i = 0 ; i < N; i ++) {
			D[i] = sc.nextLong();
		}
		for(int i = 0 ; i < N; i ++) {
			P[i] = sc.nextInt();
		}
		//开始调用递归方法,起始位置从0开始
		//由于初始无武力值,因此默认贿赂第一支怪兽
		int result = next(0,N,D,P,D[0],P[0]);
		System.out.println(result);
	}
	/**
	* index 当前位置
	* end 结束位置
	* D[] 武力值数组
	* P[] 金币数组
	* nowD 当前武力值之和
	* sumP 总共花费金币数
	*/
	public static int next(int index,int end
			,long D[],int P[]
			,long nowD,int sumP) {
		//如果当前怪兽武力值大于nowD
		//直接截断返回整数最大值(便于比较大小),减少测试路线数量
		if(D[index] > nowD) {
			return Integer.MAX_VALUE;
		}
		index ++;
		//如果走到最后位置,则返回sunP
		if(index == end) {
			return sumP;
		}
		//第一条路线,默认贿赂怪兽,递归调用下一步
		int sumP1 = next(index,end,D,P,nowD+D[index],sumP+P[index]);
		//第二条路线,默认不贿赂怪兽,递归调用下一步
		int sumP2 = next(index,end,D,P,nowD,sumP);
		//结果返回两条路线中花钱最少的sumP
		return sumP1<sumP2?sumP1:sumP2;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值