题意:给出两个数列 A[i] ,B[i];,每个数列n个数和一个k, 要求选出部分数使得 所有 a[i]的和 =所有 k*b[i]的和 ,且 a[i]的和要最大
思路:
01 背包 以 a[i] -k* b[i]作为每个物品的重量,以a[i]作为价值 ,用容量为0的背包去背 ,
可以拆成两个背包,一个装容量为正的,一个装容量为负的 dp[i] 表示的是恰好装满 容量为 i 的 价值
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000000;
const int INF = 200000;
int a[maxn];
int b[maxn];
int dp1[maxn];
int dp2[maxn];
int x1[maxn];
int y2[maxn];
int x2[maxn];
int y1v[maxn];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i = 1; i<=n; i++)
{
scanf("%d",&a[i]);
}
for(int i = 1; i<=n; i++)
{
scanf("%d",&b[i]);
b[i] = a[i] - k*b[i];
}
int cot1 =1;
int cot2= 1;
int sum1 =0;
int sum2 =0;
int res=0;
for(int i = 1; i<=n; i++)
{
//printf("%d %d\n",a[i],b[i]);
if(b[i]<0)
{
x1[cot1] = a[i];
y1v[cot1]=-b[i];
cot1++;
sum1+=y1v[cot1-1];
}
else if(b[i]>0)
{
x2[cot2]= a[i];
y2[cot2] = b[i];
cot2++;
sum2+=y2[cot2-1] ;
}
if(b[i]==0)
res+=a[i];
}
cot1--;
cot2--;
fill(dp1+1,dp1+1+sum1,-INF);
dp1[0] =0;
int c =0;
for(int i= 1; i<=cot1; i++)
{
for(int j =sum1; j>=y1v[i]; j--)
{
dp1[j] = max(dp1[j],dp1[j-y1v[i]]+x1[i]);
}
}
fill(dp2+1,dp2+1+sum2,-INF);
for(int i = 1; i<=cot2; i++)
{
for(int j = sum2; j>=y2[i]; j--)
{
dp2[j] = max(dp2[j],dp2[j-y2[i]]+x2[i]);
}
}
int ans =0;
int xvd = min(sum1,sum2);
for(int i =1 ; i<=xvd; i++)
{
ans = max(dp2[i]+dp1[i],ans);
}
ans+=res;
// printf("%d\n",ans);
if(ans<=0)
printf("-1\n");
else
printf("%d\n",ans);
}