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;
}
posted @ 2012-06-08 09:55  书山有路,学海无涯  阅读(252)  评论(0编辑  收藏  举报