HDU 1171

虽然上学期暑假的时候做过。那时是在学母函数的时候,今天看到这题的时候,第一反应却是DP。。

给出两种代码吧。   还是第一次接触二进制优化背包

第一:多重背包+二进制优化

#include <cstdlib>
#include <iostream>

using namespace std;

int v[52];
int m[52];
int f[155002];
int n,total,half;

int Max(int a,int b)
{
    return (a>b)?a:b;
}
    
void ZeroOnePake(int v)
{
    for(int i=half;i>=v;i--)
        f[i]=Max(f[i],f[i-v]+v);
}

void CompletePake(int v)
{
    for(int i=v;i<=half;i++)
        f[i]=Max(f[i],f[i-v]+v);
}
                  
void solve(int v,int m)         //算法的核心
{
    if(v*m>=half){CompletePake(v);return;}
    int k=1;
    while(k<m)
    {
        ZeroOnePake(k*v);
        m-=k;
        k<<1;
    }
    ZeroOnePake(m*v);
}
                       
int main()
{
    while(~scanf("%d",&n)&&n>=0)
    {
        if(n==0){printf("0 0\n");continue;}
        total=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&v[i],&m[i]);
            total+=v[i]*m[i];
        }
        half=total/2;
        for(int i=0;i<=total;i++) f[i]=0;
        for(int i=1;i<=n;i++)
            solve(v[i],m[i]);
        printf("%d %d\n",total-f[half],f[half]);
    }                                          
    return 0;
}


第二种:母函数


#include"stdio.h"  
#include<string.h>
int c1[130000],c2[130000];  
int main()  
{  
    struct A  
    {  
        int v;  
        int n;  
    }E[55];  
    int total;  
    int aim;  
    int i,j,k;  
    int n;  
  
  
    while(scanf("%d",&n),n>=0)  
    {  
        if(n==0)    continue;  
  
  
        total=0;  
        for(i=1;i<=n;i++)  
        {  
            scanf("%d%d",&E[i].v,&E[i].n);  
            total+=E[i].v*E[i].n;  
        }  
        aim=total/2;  
  
  
        memset(c2,0,sizeof(c2));  
        memset(c1,0,sizeof(c1));  
        for(j=0,k=0;k<=E[1].n;k++,j+=E[1].v) c1[j]=1;  
  
  
        for(i=2;i<=n;i++)  
        {  
            for(j=0;j<=aim;j++)  
            {  
                if(c1[j]==0)    continue;  
                for(k=0;k<=E[i].n;k++)  
                    c2[k*E[i].v+j]+=c1[j];  
            }  
            for(j=0;j<=aim;j++)  
            {  
                c1[j]=c2[j];  
                c2[j]=0;  
            }  
//          memset(c2,0,sizeof(c2));  
        }  
  
  
        for(i=aim;i>=0;i--)  if(c1[i]!=0)    break;  
  
  
        printf("%d %d\n",total-i,i);  
    }  
    return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值