习题:Complete the Projects (hard version)(背包DP&贪心)

题目

传送门

思路

如果\(b_i\)为正,那么能选的一定会选

现在单独考虑\(b_i\)为负的情况

我们考虑对其进行排序,

设现在的rating为r

先选i

\(r>=a_i,r+b_i>=a_j\Rightarrow r>=max(a_i,a_j-b_i)\)

先选j

\(r>=a_j,r+b_j>=a_i\Rightarrow r>=max(a_j,a_i-b_j)\)

强行让第一种情况更优,这里的更优指的是对r的限制条件

\(max(a_i,a_j-b_i)<=max(a_j,a_i-b_j)\)

很明显有\(a_i<a_i-b_j,a_j<a_j-b_i\)

既可以把式子转换为

\(a_j-b_i<=a_i-b_j\)

\(a_j+b_j<=a_i+b_i\)

即将\(a_i+b_i\)从大到小排序再进行DP即可

代码

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
struct node1
{
    int a,b;
    friend bool operator < (const node1 &a,const node1 &b)
    {
        return a.a<b.a;
    }
};
struct node2
{
    int a,b;
    friend bool operator < (const node2 &a,const node2 &b)
    {
        return a.a+a.b>b.a+b.b;
    }
};
int n,r;
vector<node1> v1;
vector<node2> v2;
int bas;
int dp[7000005];
int main()
{
    cin>>n>>r;
    for(int i=1;i<=n;i++)
    {
        int a,b;
        cin>>a>>b;
        if(b>=0)
            v1.push_back((node1){a,b});
        else
            v2.push_back((node2){a,b});
    }
    sort(v1.begin(),v1.end());
    sort(v2.begin(),v2.end());
    for(int i=0;i<v1.size();i++)
    {
        if(r>=v1[i].a)
        {
            r+=v1[i].b;
            bas++;
        }
    }
    memset(dp,-1,sizeof(dp));
    dp[r]=0;
    for(int i=0;i<v2.size();i++)
    {
        for(int j=v2[i].a;j<=r;j++)
        {
            if(dp[j]!=-1&&j+v2[i].b>=0)
            {
                dp[j+v2[i].b]=max(dp[j+v2[i].b],dp[j]+1);
            }
        }
    }
    int ans=0;
    for(int j=r;j>=0;j--)
        ans=max(ans,dp[j]);
    cout<<bas+ans;
    return 0;
}
posted @ 2020-08-24 19:39  loney_s  阅读(128)  评论(0)    收藏  举报