题目来源:https://leetcode-cn.com/problems/maximum-points-in-an-archery-competition/
大致题意:
给射箭数,和 A 的在 0 ~ 11 得分对应的区域射中数目的数组,如果 B 想拿对应得分区域的分值,就需要在对应区域的射中数目大于 A,求出 B 在相同射箭数的情况下如何获得最大得分
思路
若 B 想在某个区域得分,最优的选择是在对应区域射中 A 射中的数目 + 1
因为深度最大为 12,可以通过 DFS + 回溯 枚举所有可能,求出最大得分
DFS + 回溯
- 倒序 DFS
- 每次枚举 B 是否选择获取该区域得分,若选择获取该区域得分,还要在方法结束后回溯状态
注意边界条件:
- 枚举到得分区域 0 时,或者剩余射箭数为 0 时,终止枚举,更新最大得分
代码:
public class MaximumBobPoints {
int[] ans; // B 的射箭数对应的数组
int max; // B 的最大得分
public int[] maximumBobPoints(int numArrows, int[] aliceArrows) {
max = 0;
int n = aliceArrows.length;
int[] bobArrows = new int[n];
// 开始 DFS
dfs(aliceArrows, bobArrows, n - 1, numArrows, 0);
return ans;
}
/**
*
* @param aliceArrows A 的射箭数对应的数组
* @param bobArrows B 的射箭数对应的数组
* @param idx 目前枚举的得分区域索引
* @param num 目前 B 的剩余射箭数
* @param sum 目前 B 的得分
*/
public void dfs(int[] aliceArrows, int[] bobArrows, int idx, int num,int sum) {
if (idx < 0 || num < 0) {
return;
}
// 如果剩余射箭数为 0,或者枚举到 0 得分区域
if (num == 0 || idx == 0) {
// 更新最大得分
if (max < sum) {
max = sum;
ans = Arrays.copyOf(bobArrows, bobArrows.length);
ans[0] = num;
}
return;
}
// 不在当前区域射箭
dfs(aliceArrows, bobArrows, idx - 1, num, sum);
// 在当前区域射箭
if (num - aliceArrows[idx] >= 1) {
// 更新数组
bobArrows[idx] = aliceArrows[idx] + 1;
// 更新剩余射箭数
num -= aliceArrows[idx] + 1;
// 更新目前得分
sum += idx;
dfs(aliceArrows, bobArrows, idx - 1, num, sum);
// 回溯
bobArrows[idx] = 0;
}
}
}