问题描述
小明在出差结束后返回了公司所在的城市, 在填写差旅报销申请时, 粗心 的小明发现自己弄丢了出差过程中的票据。
为了弥补小明的损失, 公司同意小明用别的票据进行报销, 但是公司财务 要求小明提交的票据中任意两张的日期差不小于 K 天, 且总金额不得超过实际 差旅费用 M 。
比如财务要求 K=7 时, 若小明提交了一张 1 月 8 日的票据, 小明就不能 提交 1 月 2 日至 1 月 14 日之间的其他票据, 1 月 1 日及之前和 1 月 15 日及之 后的票据则可以提交。
公司的同事们一起给小明凑了 N 张票据, 小明现在想要请你帮他整理一 下, 从中选取出符合财务要求的票据, 并使总金额尽可能接近 M 。
需要注意, 由于这些票据都是同一年的, 因此 12 月底的票据不会影响到 1 月初票据的提交。这一年不是闰年。
输入格式
第 1 行: 3 个整数, N,M,K
第 2…N+1 行: 每行 3 个整数 mi,di,vi, 第 i+1 行表示第 i 张票据时间 的月份 mi 和日期 di,vi 表示该票据的面值
输出格式
第 1 行: 1 个整数, 表示小明能够凑出的最大报销金额
样例输入
4 16 3
1 1 1
1 3 2
1 4 4
1 6 8
样例输出
10
样例说明
选择 1 月 3 日和 1 月 6 日的票据
评测用例规模与约定
对于 100%100% 的评测用例, 1≤N≤1000,1≤M≤5000,1≤K≤50,1≤mi≤ 12,1≤di≤31,1≤vi≤400
日期保证合法。
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
源码:
import java.util.Arrays;
import java.util.Scanner;
public class 费用报销 {
static class node implements Comparable<node>{
int x;
int y;
public node(int x,int y) {
this.x=x; //天数
this.y=y; //价值
}
@Override
public int compareTo(node o) {
return this.x-o.x; //升序
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n=scanner.nextInt();
int m=scanner.nextInt();
int k=scanner.nextInt();
int[] w= {0,31,28,31,30,31,30,31,31,30,31,30,31};
for (int i = 1; i <= 12; i++) { //2月1日 一月的总天数+1 3月3日 1月 2月的总天数+3=w[2]+3
w[i]=w[i-1]+w[i];
}
node[] t=new node[n+1];
t[0]=new node(0, 0);
for (int i = 1; i < n+1; i++) {
int a=scanner.nextInt();
int b=scanner.nextInt();
int c=scanner.nextInt();
t[i]=new node(w[a-1]+b, c);
}
Arrays.sort(t);
int l=0;
int[][] f = new int[n+1][m+1];
for (int i = 1; i < n+1; i++) {
while(t[i].x-t[l+1].x>=k) l++; //取临近i的一个票据
for (int j = 1; j < m+1; j++) {
f[i][j]=f[i-1][j];
if (j>t[i].y) {
f[i][j]=Math.max(f[i][j], f[l][j-t[i].y]+t[i].y); //根据上一个票据转移过来的
}
}
}
System.out.println(f[n][m]);
}
}