2021 RoboCom 世界机器人开发者大赛-本科组(复赛):拼题A打卡奖励

发布于:2024-07-11 ⋅ 阅读:(20) ⋅ 点赞:(0)

拼题 A 的教超搞打卡活动,指定了 N 张打卡卷,第 i 张打卡卷需要 mi​ 分钟做完,完成后可获得 ci​ 枚奖励的金币。活动规定每张打卡卷最多只能做一次,并且不允许提前交卷。活动总时长为 M 分钟。请你算出最多可以赢得多少枚金币?

输入格式:

输入首先在第一行中给出两个正整数 N(≤103) 和 M(≤365×24×60),分别对应打卡卷的数量和以“分钟”为单位的活动总时长(不超过一年)。随后一行给出 N 张打卡卷要花费的时间 mi​(≤600),最后一行给出 N 张打卡卷对应的奖励金币数量 ci​(≤30)。上述均为正整数,一行内的数字以空格分隔。

输出格式:

在一行中输出最多可以赢得的金币数量。

输入样例:

5 110
70 10 20 50 60
28 1 6 18 22

输出样例:

40

样例解释:

选择最后两张卷子,可以在 50+60=110 分钟内获得 18+22=40 枚金币。

做法

01背包问题。

dp数组第一维是考虑了前i个卷子,第二维是花费的时间。

#include<bits/stdc++.h>
using namespace std;
int n,m;
int ans=-0x3f3f3f3f;
int a[1010],b[1010];
int dp[1010][600000];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    memset(dp,-0x3f,sizeof(dp));
    dp[0][0]=0;
    for(int i=1;i<=n;i++){//考虑前i个 
        for(int j=0;j<=m;j++){
                  if(j>=a[i])  dp[i][j]=max(dp[i][j],dp[i-1][j-a[i]]+b[i]);
                  dp[i][j]=max(dp[i][j],dp[i-1][j]);//别忘了更新当前的 
            }
    }
    for(int i=0;i<=m;i++) ans=max(ans,dp[n][i]);
    cout<<ans;
}

但是吧,dp数组超空间了,得改成1维数组。

#include<bits/stdc++.h>
using namespace std;
int n,m;
int ans=-0x3f3f3f3f;
int a[1010],b[1010];
int dp[600000];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    memset(dp,-0x3f,sizeof(dp));
    dp[0]=0;
    for(int i=1;i<=n;i++){
        for(int j=m;j>=0;j--){//倒序 
            if(j>=a[i])  dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
    	}
    }
    for(int i=0;i<=m;i++) ans=max(ans,dp[i]);
    cout<<ans;
}

这么交上去结果运行超时了,有几个的过不去。为什么呢,因为我们的m太大了。那我们就把dp数组的下标表示为金币,而不是时间。注意dp数组初始化的值

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[1010],b[1010];
int dp[30010];
int mv;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]),mv+=b[i];
    memset(dp,0x3f,sizeof(dp));//初始化的值不同
    dp[0]=0;
    for(int i=1;i<=n;i++){
        for(int j=mv;j>=0;j--){
            if(j>=b[i]) dp[j]=min(dp[j],dp[j-b[i]]+a[i]);//取最小值,因为取得相同金币,时间越少越好
        }
    }
    for(int j=mv;j>=0;j--){
        if(dp[j]<=m){
            cout<<j;
            return 0;
        }
    }
}