题意:

有n个(a,b)二元组
要求从中选出若干个二元组
满足sum(a(i))/sum(b(i))=k,其中sum(a(i))表示选中的二元组中a(i)的和,sum(b(i))同理,且式子左边需要整除
在满足该式子的同时,使得sum(a(i))尽量大,输出sum(a(i))的最大值

数据范围:n,a(i),b(i)<=100,k<=10

解法:

sum(a[i])/sum(b[i])=k
显然要先移项变为sum(a[i])=sum(b[i])*k
继续移项变为sum(a[i])-sum(b[i])*k=0
->sum(a[i])-sum(k*b[i])=0
->sum(a[i]-k*b[i])=0,同时需要sum(a[i])最大
问题可以转化为n个物品,每个物品的重量为a[i]-k*b[i],价值为a[i]
容量为0的背包恰好装满所能得到的最大价值,是一个01背包问题因为a[i]-k*b[i]可能是负数,可以给数组设置一个偏移值避免越界
也可以将正负重量分开计算,f[i]为容量i的最大价值,g[i]为容量-i的最大价值
负数重量的物品重量取反之后在dp就行了,最后的答案为f[i]+g[i]的最大值
代码里面用的是正负重量分开计算的注意背包必须装满,因此数组需要初始化为-infps:推出来的式子右边为0,一时间想不到居然有容量为0的背包,还是太年轻了

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=105;
vector<pair<int,int> >aa,bb;
int f[10000+5],g[10000+5];//f[i]表示容量i的最大值,g[i]表示容量-i的最大值
int a[maxm],b[maxm];
int n,k;
signed main(){cin>>n>>k;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)cin>>b[i];for(int i=1;i<=n;i++){int x=a[i]-k*b[i];if(x>=0)aa.push_back({x,a[i]});//正else bb.push_back({-x,a[i]});//负}for(int i=1;i<=10000;i++)f[i]=g[i]=-1e9;//背包必须装满,因此初始化为-inff[0]=g[0]=0;for(auto i:aa){int v=i.first,w=i.second;for(int j=10000;j>=v;j--){f[j]=max(f[j],f[j-v]+w);}}for(auto i:bb){int v=i.first,w=i.second;for(int j=10000;j>=v;j--){g[j]=max(g[j],g[j-v]+w);}}int ans=0;for(int i=0;i<=10000;i++){ans=max(ans,f[i]+g[i]);}if(ans==0)ans=-1;cout<<ans<<endl;return 0;
}

是我菜了
原创文章 479获赞 37访问量 3万+
关注私信
展开阅读全文