ICPC Southeastern Europe Contest 2019 B. Level Up(DP)

题目链接
题目大意:
总共要升两级,有n个任务,每个任务有在第一级时候所获得的经验值和所需的时间,每个任务也有在第二级的时候所获得的经验值和所需的时间。其中第一级升级之后多余的经验放入第二级。问升两级所需要的最少时间是多少?如果不能就输出-1。

解题思路:
定义dp[i][j]为获得第一级经验为i,第二级经验为j所需要的最少时间,可以考虑使用01背包逆序求解以减少第几个任务的这个维度。
重点:需要对第一级的经验进行升序排序后,否则顺序会影响dp结果。如果第一级经验分别为:90,40,40,且第一级所需要的经验为100,则溢出情况只有130这种情况,但是40,40,90就有40+90=130,40+40+90=170两种情况,所以要进行升序排序,不然会有情况遗漏。

解题代码:

#include<bits/stdc++.h>
using namespace std;
mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const ll maxn=2e5+10;
ll inf=1e18;
ll dp[1010][1010];
struct E{
    int x,t,y,r;
}p[505];
bool cmp(E a1,E a2)
{
    return a1.x<a2.x;
}
int main()
{
    ll n,s1,s2;
    cin>>n>>s1>>s2;
    for (ll i=0;i<=1000;i++)
    {
        for (ll j=0;j<=1000;j++)
        dp[i][j]=inf;
    }
    dp[0][0]=0;
    for (ll i=1;i<=n;i++)
    {
        cin>>p[i].x>>p[i].t>>p[i].y>>p[i].r;
    }
    sort(p+1,p+1+n,cmp);
    for (ll i=1;i<=n;i++)
    {
        for (ll j=1000;j>=0;j--)
        {
            for (ll k=1000;k>=0;k--)
            {
                ll t1=inf,t2=inf;
                if (j>=p[i].x && j-p[i].x<s1)
                t1=dp[j-p[i].x][k]+p[i].t;

                if (k>=p[i].y)
                t2=dp[j][k-p[i].y]+p[i].r;
             
                dp[j][k]=min(dp[j][k],min(t1,t2));
            }
        }
    }
    ll ans=inf;
    for (ll j=s1;j<=1000;j++)
    {
        for (ll k=max(0ll,s2-(j-s1));k<=1000;k++)
        {
            ans=min(ans,dp[j][k]);
        }
    }
    if (ans==inf)
    ans=-1;
    cout<<ans;
    return 0;
}
发布了12 篇原创文章 · 获赞 1 · 访问量 327

猜你喜欢

转载自blog.csdn.net/qq_41818939/article/details/105527105