You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
3.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_08_3_week;
// 来自学员问题
// 给定怪兽的血量为hp
// 第i回合如果用刀砍怪兽在这回合会直接掉血没有后续效果
// 第i回合如果用毒怪兽在这回合不会掉血
// 但是之后每回合都会掉血,并且所有中毒的后续效果会叠加
// 给定的两个数组cuts、poisons两个数组等长长度都是n
// 表示你在n回合内的行动
// 每一回合的刀砍的效果由cuts[i]表示
// 每一回合的中毒的效果由poisons[i]表示
// 如果你在n个回合内没有直接杀死怪兽意味着你已经无法有新的行动了
// 但是怪兽如果有中毒效果的话那么怪兽依然会在hp耗尽的那回合死掉
// 返回你最快能在多少回合内将怪兽杀死
// 数据范围 :
// 1 <= n <= 10的5次方
// 1 <= hp <= 10的9次方
// 1 <= cuts[i]、poisons[i] <= 10的9次方
public class Code02_CutOrPoison {
// 不算好的方法
// 为了验证
public static int fast1(int[] cuts, int[] poisons, int hp) {
int sum = 0;
for (int num : poisons) {
sum += num;
}
int[][][] dp = new int[cuts.length][hp + 1][sum + 1];
return process1(cuts, poisons, 0, hp, 0, dp);
}
public static int process1(int[] cuts, int[] poisons, int index, int restHp, int poisonEffect, int[][][] dp) {
restHp -= poisonEffect;
if (restHp <= 0) {
return index + 1;
}
// restHp > 0
if (index == cuts.length) {
if (poisonEffect == 0) {
return Integer.MAX_VALUE;
} else {
return cuts.length + 1 + (restHp + poisonEffect - 1) / poisonEffect;
}
}
if (dp[index][restHp][poisonEffect] != 0) {
return dp[index][restHp][poisonEffect];
}
int p1 = restHp <= cuts[index] ? (index + 1)
: process1(cuts, poisons, index + 1, restHp - cuts[index], poisonEffect, dp);
int p2 = process1(cuts, poisons, index + 1, restHp, poisonEffect + poisons[index], dp);
int ans = Math.min(p1, p2);
dp[index][restHp][poisonEffect] = ans;
return ans;
}
// 真正想实现的方法
// O(N * log(hp))
public static int fast2(int[] cuts, int[] poisons, int hp) {
// 怪兽可能的最快死亡回合
int l = 1;
// 怪兽可能的最晚死亡回合
int r = hp + 1;
int m = 0;
int ans = Integer.MAX_VALUE;
while (l <= r) {
m = l + ((r - l) >> 1);
if (ok(cuts, poisons, hp, m)) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans;
}
public static boolean ok(int[] cuts, int[] posions, long hp, int limit) {
int n = Math.min(cuts.length, limit);
for (int i = 0, j = 1; i < n; i++, j++) {
hp -= Math.max((long) cuts[i], (long) (limit - j) * (long) posions[i]);
if (hp <= 0) {
return true;
}
}
return false;
}
// 为了测试
public static int[] randomArray(int n, int v) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * v) + 1;
}
return ans;
}
// 为了测试
public static void main(String[] args) {
int N = 30;
int cutV = 20;
int posionV = 10;
int hpV = 200;
int testTimes = 10000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 1;
int[] cuts = randomArray(n, cutV);
int[] posions = randomArray(n, posionV);
int hp = (int) (Math.random() * hpV) + 1;
int ans1 = fast1(cuts, posions, hp);
int ans2 = fast2(cuts, posions, hp);
if (ans1 != ans2) {
System.out.println("出错了!");
}
}
System.out.println("测试结束");
}
}