解题思路:先把月份和天数换算成一年第几天,然后从小到大排序。然后进行动态规划,dp[i][j]表示选到第i个为止时金额j是否能取到,last代表第i个之前的最近的距离i时间差大于等于k的序号。如果没有last就等于0。状态转移方程:dp[i][j] = dp[i - 1][j] | (j >= a[i].v ? dp[last][j - a[i].v] : 0)
注意事项:
每个序号转移之前可以先把的dp[i-1]复制过来。因为前一个的天数要小于等于这一个,所以到前一个的天数位置能取到的到这一个的天数肯定也能取到。
参考代码:
#include <bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define endl "\n"
#define pb push_back
#define getl(s) getline(cin,s)
#define max(a,b) a > b ? a : b
#define min(a,b) a < b ? a : b
#define abs(a) a > 0 ? a : -a
#define lowbit(a) a & -a
using namespace std;
const int N = 1e3 + 5;
const int M = 5e3 + 5;
struct node
{
int day,v;
}a[N];
int n,m,k,dp[N][M];//dp[i][j]代表选择到第i个时金额j是否能取到
int mon[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int getday(int m,int d)
{
int res = 0;
for(int i = 0;i < m;i++)
res += mon[i];
return res + d;
}
bool cmp(node x,node y)
{
return x.day < y.day;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>k;
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i = 1;i <= n;i++)
{
dp[i][0] = 1;
int m,d;cin>>m>>d>>a[i].v;
a[i].day = getday(m,d);
}
//按照时间先后顺序排列
sort(a + 1,a + n + 1,cmp);
for(int i = 1;i <= n;i++)
{
int last = i - 1;
//找到最近的距离i超过k天的序号
while(a[i].day - k < a[last].day && last > 0)last--;
for(int j = m;j >= 0;j--)
{
dp[i][j] = dp[i - 1][j];
if(j >= a[i].v)dp[i][j] |= dp[last][j - a[i].v];
}
}
for(int i = m;i >= 0;i--)
if(dp[n][i])
{
cout<<i;
break;
}
return 0;
}0.0分
15 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复