java打怪升级代码_1255: 打怪升级(Java)
Description
對(duì)于多數(shù)RPG游戲來(lái)說(shuō),除了劇情就是打怪升級(jí)。本題的任務(wù)是用最短的時(shí)間取得所有戰(zhàn)斗的勝利。這些戰(zhàn)斗必須按照特定的順序進(jìn)行,每打贏一場(chǎng),都可能會(huì)獲得一些補(bǔ)藥,用來(lái)提升力量。本題只有兩種補(bǔ)藥:“加1藥”和“乘2藥”,分別讓你的力量值加1和乘以2。
戰(zhàn)斗時(shí)間取決于你的力量。每場(chǎng)戰(zhàn)斗可以用6個(gè)參數(shù)描述:p1, p2, t1, t2, w1, w2。如果你的力量小于p1,你將輸?shù)魬?zhàn)斗;如果你的力量大于p2,需要t2秒贏得戰(zhàn)斗;如果力量位于p1和p2(包括p1和p2),戰(zhàn)斗時(shí)間從t1線性遞減到t2。比如p1=50,p2=75,t1=40,t2=15,你的力量為55,則戰(zhàn)斗獲勝需要35秒。注意,戰(zhàn)斗時(shí)間可能不是整數(shù)。最后兩個(gè)參數(shù)w1和w2分別表示戰(zhàn)斗勝利后獲得的“加1藥”和“乘2藥”的數(shù)量。注意,你不一定要立刻使用這些補(bǔ)藥,可以在需要的時(shí)候再用,但不能在戰(zhàn)斗中使用補(bǔ)藥。
按順序給出每場(chǎng)戰(zhàn)斗的參數(shù),輸出贏得所有戰(zhàn)斗所需的最短總時(shí)間。戰(zhàn)斗必須按順序進(jìn)行,且不能跳過(guò)任何一場(chǎng)戰(zhàn)斗。
Input
輸入最多包含25組測(cè)試數(shù)據(jù)。每組數(shù)據(jù)第一行為兩個(gè)整數(shù)n和p(1<=n<=1000, 1<=p<=100),即戰(zhàn)斗的場(chǎng)數(shù)和你的初始力量值。以下n行每行6個(gè)整數(shù)p1, p2, t1, t2, w1, w2(1<=p1
Output
對(duì)于每組數(shù)據(jù),輸出最短總時(shí)間(單位:秒),保留兩位小數(shù)。如果無(wú)解,輸出“Impossible”(不含引號(hào))。
Sample Input
1 55
50 75 40 15 10 0
2 55
50 75 40 15 10 0
50 75 40 15 10 0
3 1
1 2 2 1 0 5
1 2 2 1 1 0
1 100 100 1 0 0
1 7
4 15 35 23 0 0
1 1
2 3 2 1 0 0
0 0
Sample Output
35.00
60.00
41.00
31.73
Impossible
題目分析
讀完這個(gè)題目,我們首先應(yīng)該想到的是,這兩瓶藥水應(yīng)該怎么用。
我們都知道:當(dāng)力量越大的時(shí)候,“乘2藥”的作用就越大,比如:力量為1,用了“乘2藥”后,力量增加到了2;力量為2,用了“乘2藥”,力量就增加到了4。因此,我們需要用搜索遍歷的方法來(lái)計(jì)算最終用時(shí),按照“乘2藥”使用的瓶數(shù)來(lái)遍歷。因此我們要討論的問(wèn)題是:戰(zhàn)斗結(jié)束,你是否使用“乘2藥”,用的話,你會(huì)用幾瓶。
大致需要注意哪些:首先我們要知道搜索什么時(shí)候結(jié)束;力量值不能戰(zhàn)斗勝利怎么辦,力量值已經(jīng)超過(guò)了此次戰(zhàn)斗最大的力量值我們?cè)趺刺幚?。這3個(gè)問(wèn)題弄明白之后,基本上就能解決了。
“加1藥”只要有就用掉,它越早用越好,沒(méi)必要留到后面用。
以上就是題目的粗略分析,不是很清楚的話,可以看代碼,自認(rèn)為注釋非常詳細(xì)了。
代碼
// 1262ms
import java.util.Scanner;
public class Main {
// 關(guān)卡類,記錄每場(chǎng)戰(zhàn)斗的信息
private class Combat {
// 前面6個(gè)是輸入的數(shù)據(jù),即戰(zhàn)斗的信息
// gapP = p2 - p1后面計(jì)算用的比較頻繁,直接算出來(lái)比較好
// gapT = t1- t2同上
int p1, p2, t1, t2, w1, w2, gapP, gapT;
}
private Combat[] combat;// 記錄所有戰(zhàn)斗的信息,下標(biāo)從0開(kāi)始
private Scanner sc;
private int n, p;// 戰(zhàn)斗場(chǎng)數(shù),初始戰(zhàn)力值
private double totalTime;// 所有戰(zhàn)斗勝利用時(shí),即最終結(jié)果
// battle()方法中要用到
private int newPower;// 新力量值
private int newBottles;// 新藥水?dāng)?shù)量
private double newUsedTime;// 新用時(shí)
// 當(dāng)前力量值與最低力量值的差,同最大力量差的比值,用于計(jì)算當(dāng)前戰(zhàn)斗用時(shí)
private double scale;
public Main() {
sc = new Scanner(System.in);
int i;
// 申請(qǐng)堆空間
combat = new Combat[1001];
for(i = 0; i < 1001; i++) {
combat[i] = new Combat();
}
while(input()) {
totalTime = Double.MAX_VALUE;// 賦最大值
battle(0, p, 0, 0);// 初始勝利0場(chǎng),力量值p,藥水0瓶,用時(shí)0秒
if(totalTime == Double.MAX_VALUE) {
System.out.println("Impossible");
} else {
System.out.printf("%.2f", totalTime);
System.out.println();
}
}
sc.close();
}
/**
* @return 是否結(jié)束輸入
*/
private boolean input() {
n = sc.nextInt();
p = sc.nextInt();
if(0 == n) {
return false;
}
int i;
for(i = 0; i < n; i++) {
combat[i].p1 = sc.nextInt();
combat[i].p2 = sc.nextInt();
combat[i].t1 = sc.nextInt();
combat[i].t2 = sc.nextInt();
combat[i].w1 = sc.nextInt();
combat[i].w2 = sc.nextInt();
// 計(jì)算差值
combat[i].gapP = combat[i].p2 - combat[i].p1;
combat[i].gapT = combat[i].t1 - combat[i].t2;
}
return true;
}
/**
* @param wons已經(jīng)勝利戰(zhàn)斗數(shù)量
* @param power上一次戰(zhàn)斗結(jié)束時(shí)候的力量值
* @param bottles目前“乘2藥”的瓶數(shù)
* @param usedTime勝利wons場(chǎng)戰(zhàn)斗用的時(shí)間
*/
private void battle(int wons, int power, int bottles, double usedTime) {
// 如果已經(jīng)用的時(shí)間超過(guò)了目前的最短時(shí)間
// 后面的戰(zhàn)斗也就沒(méi)必要了,直接退出
if(usedTime > totalTime) {
return;
}
// 所有戰(zhàn)斗都勝利了
if(wons == n) {
// 如果用時(shí)比目前最短時(shí)間還少的話
if(usedTime < totalTime) {
totalTime = usedTime;// 更新最短時(shí)間記錄
}
return;// 退出
}
int i;
// 這是最后一場(chǎng)戰(zhàn)斗,戰(zhàn)斗前將藥水用完,不用就浪費(fèi)了
if(wons == n - 1) {
for(i = 0; i < bottles; i++) {
power *= 2;
}
bottles = 0;
}
// 循環(huán)考慮怎么處理剩余的藥水
for(i = 0; i <= bottles; i++) {
if(i > 0) {
// i等于0的時(shí)候,表示不用藥水,不能乘2;其他情況,每次用1瓶
power *= 2;
}
// 力量值不低于當(dāng)前戰(zhàn)斗要求的最低力量值,才能繼續(xù)戰(zhàn)斗;否則循環(huán),繼續(xù)用藥水
if(power >= combat[wons].p1) {
// 力量值不低于要求最高力量值
if(power >= combat[wons].p2) {
// 力量值已經(jīng)超過(guò)了最大值100
if(power >= 100) {
// 后面的所有戰(zhàn)斗,將會(huì)以最快速度結(jié)束
for(i = wons; i < n; i++){
usedTime += combat[i].t2;
}
battle(n, power, 0, usedTime);
break;
}
// 當(dāng)前戰(zhàn)斗勝利,將“加1藥”全部用完
newPower = power + combat[wons].w1;
// 原來(lái)有bottles瓶,用了i瓶,當(dāng)前戰(zhàn)斗勝利,獲得了w2瓶
newBottles = bottles - i + combat[wons].w2;
newUsedTime = usedTime + combat[wons].t2;
battle(wons + 1, newPower, newBottles, newUsedTime);
break;// 這個(gè)break很關(guān)鍵,沒(méi)有的話會(huì)超時(shí),親測(cè)...
} else {// 力量值低于最高力量值
newPower = power + combat[wons].w1;
newBottles = bottles - i + combat[wons].w2;
// 下面3行,計(jì)算當(dāng)前戰(zhàn)斗用時(shí)
scale = (power - combat[wons].p1) * 1.0 / combat[wons].gapP;
newUsedTime = usedTime;
newUsedTime += combat[wons].t1 - scale * combat[wons].gapT;
battle(wons + 1, newPower, newBottles, newUsedTime);
}
}
}
}
public static void main(String[] args) {
new Main();
}
}
代碼補(bǔ)充
可能大家在Java里面數(shù)組內(nèi)存比較喜歡——用多少,就申請(qǐng)多少這種做法(反正我是這樣的),但是這個(gè)題目,由于搜索開(kāi)銷較大,我們應(yīng)該從開(kāi)銷方面來(lái)考慮如何寫(xiě)代碼。題目指明可能有1000場(chǎng)戰(zhàn)斗,也就是數(shù)組要1000大小,這么大的申請(qǐng)堆空間的時(shí)間開(kāi)銷還是很大的。我提交的相差了大約500ms,很可怕。所以此題應(yīng)該直接一次性申請(qǐng)堆空間1001大小。
代碼中有幾個(gè)地方用到了break,這里主要是為了除去不必要的遍歷,以節(jié)約時(shí)間。這種做法也就是我們通常說(shuō)的剪枝,自認(rèn)為剪的還不夠好。如果大家通過(guò)閱讀代碼之后想到了更好的方法(也就是提交時(shí)間更短),或者還有疑問(wèn)的話,歡迎評(píng)論以及留言(郵箱在友情鏈接),我會(huì)及時(shí)回復(fù)。
小結(jié)
這個(gè)題目并沒(méi)有我們想象的難,主要是注意一些細(xì)節(jié)問(wèn)題。這道題目還檢查出了我的關(guān)于內(nèi)部類知識(shí)的漏洞,申請(qǐng)類對(duì)象數(shù)組需要兩次new,否則知識(shí)申請(qǐng)了一個(gè)數(shù)組,并沒(méi)有實(shí)例。有這個(gè)疑問(wèn)的可參考我自己寫(xiě)的與此對(duì)應(yīng)的博客給內(nèi)部類對(duì)象數(shù)組屬性賦值時(shí)報(bào)錯(cuò):Exception in thread “main” java.lang.NullPointerException。
總結(jié)
以上是生活随笔為你收集整理的java打怪升级代码_1255: 打怪升级(Java)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 使用 .NET HttpClient
- 下一篇: Java 生成 OFD 文档