第一题
题目大意:
给出一组有序的旅游景点,到达该景点会获取不同的分数作为奖励。参加比赛的选手都从第一站开始,自动会获取该景点的分数。每位参赛者会有一组数值一样的卡片,每张卡片上有一个数字1,2,3或者4,不同的数字代表前进的步数。如何使用卡片前进,会使得获得的分数最大。
输入:scores数组代表当前给出的各个景点的分数
cards数组代表当前给出的卡片
求获得的最高的分数
思路:
线性DP求解
首先统计出每个卡片数字的个数,保存在一个一维数组中
然后创建一个四维的dp数组,数组的索引就是每个卡片数字的个数.
相当于对四种卡片进行组合,每种数字最多有40个,每一次都选择前一次的最优的走法,所以最后一定是全局最优的.
代码:
import java.util.*;
public class Main1{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] scores = new int[n];
for(int i=0;i<n;i++){
scores[i]=sc.nextInt();
}
int m = sc.nextInt();
int[] cards = new int[m];
for(int i=0;i<m;i++){
cards[i] = sc.nextInt();
}
System.out.println(solution(scores, cards));
}
public static int solution(int[] scores, int[] cards){
int[] num = new int[5];
int[][][][] dp = new int[41][41][41][41];
for(int i=0;i<cards.length;i++){
num[cards[i]]++;
}
dp[0][0][0][0] = scores[0];
for(int i=0;i<=num[1];i++){
for(int j=0;j<=num[2];j++){
for(int m=0;m<=num[3];m++){
for(int n=0;n<=num[4];n++){
int pos = i+j*2+m*3+n*4;
if(i!=0){
dp[i][j][m][n] = Math.max(dp[i][j][m][n],
dp[i-1][j][m][n]+scores[pos]);
}
if(j!=0){
dp[i][j][m][n] = Math.max(dp[i][j][m][n],
dp[i][j-1][m][n]+scores[pos]);
}
if(m!=0){
dp[i][j][m][n] = Math.max(dp[i][j][m][n],
dp[i][j][m-1][n]+scores[pos]);
}
if(n!=0){
dp[i][j][m][n] = Math.max(dp[i][j][m][n],
dp[i][j][m][n-1]+scores[pos]);
}
}
}
}
}
return dp[num[1]][num[2]][num[3]][num[4]];
}
}
第二题
题目大意:
租车店只剩下一辆车可以租,但是一天内有n个订单,每个订单的用车开始时间为第X小时,用车结束时间为Y小时,订单金额为Z,计算怎样安排订单可以获得的最大收益
输入:整数n(1<=n<=10),表示n个订单
读入用空格分隔的整数,表示订单的开始时间
读入用空格分隔的整数,表示订单的结束时间
读入用空格分隔的整数,表示订单金额
4
1 2 3 3
3 4 5 6
200 150 180 210
输出 410
思路:
还是考虑动态规划做,回溯应该也可以,可能会超时.这题是最大收益问题.
首先考虑当前时间段的订单选择还是不选择,如果不选择那么收益为前一个时间段获得的最大收益,如果选择,就必须找到符合当前时间段的前一个时间段的订单最大收益,再加上当前时间段的收益.
状态转移方程: dp[i] = Math.max(dp[i-1], dp[pre[i]]+value)
所以需要维护一个pre数组,存储当前时间段的前一个可以完成的订单所在的索引.如果前面没有符合的订单就置为-1.
这一题当时没有提交成功,此代码为之后完成的,如果代码有问题,不能通过用例,希望大家可以提出来,虚心接受大家的指导和建议,继续将代码完善.
代码:
import java.util.*;
public class Main1{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = Integer.parseInt(sc.nextLine());
String[] start = sc.nextLine().trim().split(" ");
String[] end = sc.nextLine().trim().split(" ");
String[] value = sc.nextLine().trim().split(" ");
int[][] data = new int[n][3];
for(int i=0;i<n;i++){
data[i][0] = Integer.parseInt(start[i]);
data[i][1] = Integer.parseInt(end[i]);
data[i][2] = Integer.parseInt(value[i]);
}
System.out.println(solution(data));
}
public static int solution(int[][] data) {
//维护一个与当前时间段不冲突的最近一次时间段的索引
int[] pre = new int[data.length];
//先全部填充-1,没有满足的索引就保持-1
Arrays.fill(pre, -1);
for(int i=1;i<data.length;i++){
for(int j=i-1;j>=0;j--){
if(data[j][1]<=data[i][0]){
//找到与当前时间段最近的复合的索引,并记录
pre[i]=j;
break;
}
}
}
int[] dp = new int[data.length];
dp[0]=data[0][2];
for(int i=1;i<data.length;i++){
if(pre[i]!=-1){
dp[i] = Math.max(dp[i-1],dp[pre[i]]+data[i][2]);
}else if(pre[i]==-1){
dp[i] = Math.max(dp[i-1],data[i][2]);
}
}
return dp[data.length-1];
}
}