题目:游戏网站提供若干升级补丁,每个补丁大小不一,玩家要升级到最新版,如何选择下载哪些补丁下载量最小。
输入:
第一个数为用户版本 第二个数为最新版本,空格分开
接着输入N行补丁数据 第一个数补丁开始版本 第二个数为补丁结束版本 第三个数为补丁大小,空格分开
样例输入
1000 1050
1000 1020 50
1000 1030 70
1020 1030 15
1020 1040 30
1030 1050 40
1040 1050 20
输出
对于每个测试实例,输出一个升级路径以及最后实际升级的大小
样例输出
1000->1020->1040->1050(100)
分析:求最小下载量,可以使用dp思想,dp[j]=min(dp[j],dp[i]+size),其中i为补丁开始版本,j为补丁结束版本,size为补丁大小,最后直接取dp中最新版本的位置即为最小下载大小
要求同时输出最短升级路径,这里在求出dp之后反向推导升级路径,即对于每行输入,当dp[i]=dp[j]-size时,i即为升级路径,因为升级路径可能不止一条,所以从头开始遍历,即两重for循环,第一层从最新版本向前推导,第二层从头向后寻找最少的升级路径
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
static int[] flag;
static ArrayList<int[]> al;
static int min = Integer.MAX_VALUE;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
al = new ArrayList<int[]>();
int star = in.nextInt();
int end = in.nextInt() - star;
int max = 0;
//因为没有标注N为多少,只能用hasnext来判断是否输入结束
while(in.hasNext()) {
int[] te = new int[3];
te[0] = in.nextInt() - star;
te[1] = in.nextInt() - star;
te[2] = in.nextInt();
al.add(te);
max = Math.max(max, te[1]);
}
int len = al.size();
flag = new int[max + 1];
Arrays.fill(flag, Integer.MAX_VALUE);
fun();
ArrayList<Integer> al1=fun1(max);
StringBuilder sb =new StringBuilder();
for(int i=al1.size()-1;i>=0;i--) {
int num=al1.get(i);
sb.append(num+1000+"->");
}
sb.delete(sb.length()-2, sb.length());
sb.append("("+flag[max]+")");
System.out.println(sb.toString());
}
public static void fun() {
for (int i = 0; i < al.size(); i++) {
int[] temp = al.get(i);
if (temp[0] == 0) {
flag[temp[1]] = temp[2];
} else {
flag[temp[1]] = Math.min(flag[temp[0]] + temp[2], flag[temp[1]]);
}
}
}
static ArrayList<Integer> fun1(int end) {
ArrayList<Integer> al1=new ArrayList<Integer>();
al1.add(end);
int end1=end;
for(int i=al.size()-1;i>=0;i--) {
for(int j=0;j<al.size();j++) {
int[] temp = al.get(j);
if(temp[1]==end1) {
if(flag[temp[0]]==flag[end1]-temp[2]) {
end1=temp[0];
al1.add(end1);
break;
}
}
}
}
al1.add(0);
return al1;
}
}