蓝桥杯每日一题

题目链接:https://www.lanqiao.cn/problems/2195/learning/

费用报销

分析:

就是选和不选经典的01背包问题,具体描述看代码备注。

题目描述:

#include <iostream>
#include <algorithm>
using namespace std;
int n , M , k;  //n张票据,M最大费用,日期差不小于k
const int N = 1010;  //数据范围
int d[N] , me[N];  //d[]表示当前这天到1月1号的天数,me[]表示这天金额
int dp[N][5010] , ne[N][5010];  //dp[i][j]在前i个中选不超过j元的最大值,ne[][]当前选择的了前i个中的哪个
int sum[13] = {0 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31};  //月份对应对的天数

struct Edge{
  pair<int , int> a;  //方便按日期排序
  int me;
  bool operator < (const Edge & A)const{   //重写小于
    return a < A.a;
  }
}Edge[N];

int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> M >> k;
  for(int i = 1;i <= n;i++)  //输入n个数据
  {
    int m , t , e;
    cin >> m >> t >> e;
    Edge[i].a = {m , t};
    Edge[i].me = e;
  }
  sort(Edge + 1, Edge + n + 1);  //日期从小到大排序
  for(int i = 1;i <= n;i++)  //计算到1月1号的天数(包含1月1号这天)
  {
      for(int j = 1;j < Edge[i].a.first;j++)
      {
          d[i] += sum[j];
      }
    d[i] += Edge[i].a.second;
  }
  for(int i = 1;i <= n;i++)
  {
    for(int j = 0;j <= M;j++)
    {
      if(i > 1)  //除第一个数据记录先不选自己的值
      {
        dp[i][j] = dp[i - 1][j];
        ne[i][j] = ne[i - 1][j];
      }
      if(j >= Edge[i].me)
      {
        if(dp[i][j] < dp[i - 1][j - Edge[i].me] + Edge[i].me)  //如果产生最大值
        {
          if(ne[i - 1][j - Edge[i].me] == 0 || d[i] - d[ne[i - 1][j - Edge[i].me]] >= k) 
            //且要么前面没选要么日期差大于k
          {
            dp[i][j] = dp[i - 1][j - Edge[i].me] + Edge[i].me;
            ne[i][j] = i;
          }
          else  //如果产生最大值但是不能选则保持原样
          {
              dp[i][j] = dp[i][j - 1];
              ne[i][j] = ne[i][j - 1];
          }
        }
      }
    }
  }
  cout << dp[n][M];  //输出最后的答案
  return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值