poj 2184

真是一个好题啊,还是想了好几天而且还WA了两次…….

令res[i][j]表示前i个COW,Si为j时Fi的最大值。

res[i][j]=max(res[i-1][j-Fi[i]],res[i][j]); 因为res[i][]只与res[i-1][]有关空间复杂度省去一维,就像01背包那样。因为j可能为负值,因此我们可以将j设置一个偏移量MOVE。

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

#define MAX 1234567890

#define MOVE 100000

int Si[110],Fi[110],res[200010];

int max(int a,int b)

{

    return a > b ? a : b;

}

int work(int n,int end,int start)

{

    int i,j,Max;

    for(i=start;i<=end;i++) res[i]=-MAX;

    for(i=1;i<=n;i++)

    {

        if(Si[i]>0)

        {

            for(j=end;j>=start+Si[i];j--)

            {

                if(res[j-Si[i]]!=-MAX) 

                    res[j]=max(res[j-Si[i]]+Fi[i],res[j]);

            }

            res[MOVE+Si[i]]=max(Fi[i],res[MOVE+Si[i]]);

        }

        else

        {

            for(j=start;j<=end+Si[i];j++)

            {

                if(res[j-Si[i]]) 

                    res[j]=max(res[j-Si[i]]+Fi[i],res[j]);

            }

            res[MOVE+Si[i]]=max(Fi[i],res[MOVE+Si[i]]);

        }

    }

    Max=0;

    for(i=MOVE;i<=end;i++)

    {

        if(res[i]>=0 && i-MOVE+res[i] > Max ) Max=i-MOVE+res[i];

    }

    return Max;

}

int main()

{

    int i,n,sum1,sum2,f,s;

    while(scanf("%d",&n)!=EOF)

    {

        sum1=sum2=0;

        memset(res,0,sizeof(res));

        for(i=1;i<=n;i++) 

        {

            scanf("%d %d",&s,&f);

            Si[i]=s;   Fi[i]=f;

            s > 0 ? sum1+=s : sum2+=s;

        }

        printf("%d\n",work(n,sum1+MOVE,sum2+MOVE));

    }

    return 0;

}

你可能感兴趣的:(poj)