将月份和天数转化为天数很妙,用map存储月和日对应的天数,需要时查找就好
//本题是动态规划的01背包问题,将日期视为体积,报销金额视为价值
//对于第i天,其状态从第i-k天递推而来(i-k>0,否则为0)
//在总报销金额不超过m的情况下,第i天的报销金额可以选择也可以不选
//若选择则为dp[i]+dp[i-k],若不选择则dp[i]=dp[i-1]
//若累加第i天后总报销金额超过了m,则dpi]只能用dp[i-1]更新
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int dp[N];//dp[i]表示截止到本年第i天,所能报销的最大金额
map<pair<int,int>,int>mp;//将<月,日>映射为本年的第几天
int month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};//month[i]存储第i个月的天数(不是闰年)
int n,m,k;
void get_day()//初始化,将本年内的每个日期映射为天数
{
int day=0;
for(int i=1;i<=12;i++)
{
for(int j=1;j<=month[i];j++)
{
day++;
mp[make_pair(i,j)]=day;
}
}
}
int main()
{
get_day();//初始化
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)//输入n个票据
{
int mon,day,value;
scanf("%d%d%d",&mon,&day,&value);//输入月、日和报销金额
int date=mp[make_pair(mon,day)];//获取该<月,日>对应的天数
dp[date]=max(dp[date],value);//第date天的最大报销金额等于同一天内的最大面值的票据
}
for(int i=1;i<=365;i++)//遍历本年度内的每一天
{
int pre=max(0,i-k);//计算上一个能累加报销金额的日期:k天之前(不能小于0)
if(dp[i]+dp[pre]<=m)//若上一次累加上本次的金额不超过m,说明可以累加
{
dp[i]=max(dp[i-1],dp[i]+dp[pre]);
//累加上一次,为dp[i]+dp[pre];
//不累加上一次,为dp[i-1]
//二者取最大值更新dp[i]
}
else dp[i]=dp[i-1];//上一次累加本次的金额已经超过了m,一定不能累加,只能与前一天相同
}
printf("%d\n",dp[365]);//递推完毕,最大报销金额在dp数组的最末尾
return 0;
}