1. 程式人生 > >演算法提高 求最大值 DP

演算法提高 求最大值 DP

問題描述   給n個有序整數對ai bi,你需要選擇一些整數對 使得所有你選定的數的ai+bi的和最大。並且要求你選定的數對的ai之和非負,bi之和非負。 輸入格式   輸入的第一行為n,數對的個數
  以下n行每行兩個整數 ai bi 輸出格式   輸出你選定的數對的ai+bi之和 樣例輸入 5
-403 -625
-847 901
-624 -708
-293 413
886 709 樣例輸出 1715 資料規模和約定   1<=n<=100
  -1000<=ai,bi<=1000

DP[i][j]=k. 表示的是利用前i個, a的和為j時,b的和為k。

那麼dp[i][j]=max(dp[i][j],dp[i-1][j]);

如果j-a[u]存在,則dp[i][j]=max(dp[i][j],dp[i-1][ja[u]]+b[i];

輸出時遍歷j,ans=max(ans,j+dp[n-1][j])

由於a的和的和可能是負的,我們都加一個100000,保證他是正的

#include<bits/stdc++.h>
using namespace std;
int a[110];
int b[110];
int dp[110][210000];//用前i個組成a和為j的情況,b的和為多少
int n,p,q;
int t=100000;
 const int INF = 0x3f3f3f3f;
int solve(int n)
{
    for(int i=0;i<n;i++)
    {
        for(int j=-t;j<=t;j++)
        {
            dp[i][j+t]=-INF;
        }
    }
    for(int i=0;i<n;i++)
    {
        dp[i][a[i]+t]=b[i];
    }
    for(int i=1;i<n;i++)
    {
        for(int j=-t;j<=t;j++)
        {
            dp[i][j+t]=max(dp[i-1][j+t],dp[i][j+t]);
            if(j+t-a[i]>=0&&j+t-a[i]<=200000)
            dp[i][j+t]=max(dp[i][j+t],dp[i-1][j+t-a[i]]+b[i]);
        }
    }
    int ans=-INF;
    for(int j=0;j<=t;j++)
    {
       if(dp[n-1][j+t]>=0)
        ans=max(ans,j+dp[n-1][j+t]);
       else
        ans=max(ans,-INF);
    }
    return ans;
}
int main()
{
    cin>>n;
    int cnt=0;
    for(int i=0;i<n;i++)
    {
        cin>>p>>q;
        if(p<0&&q<0)
        {
            continue;
        }
        a[cnt]=p;
        b[cnt]=q;
        cnt++;
    }
    int ans=solve(cnt);
    if(ans<=-INF)
    {
        cout<<"0"<<endl;
    }
    else
    {
        cout<<ans<<endl;
    }
}