最大的中位数
Applese有1个容量为v的背包,有n个物品,每一个物品有一个价值ai,以及一个大小bi
然后他对此提出了自己的疑问,如果我不要装的物品装的价值最大,只是一定需要装m个物品,要使得求出来的物品价值的中位数最大
Applese觉得这个题依然太菜,于是他把这个问题丢给了你
当物品数量为偶数时,中位数即中间两个物品的价值的平均值
链接:https://ac.nowcoder.com/acm/problem/17315
输入描述:
第一行三个数v, n, m,分别代表背包容量,物品
#include<bits/stdc++.h> using namespace std; typedef pair<int,int> PII; PII a[100005]; int v,n,m; int l[100005]; int r[100005]; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>v>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i].first>>a[i].second; } sort(a,a+n);//按价值从小到大排序 int temp1,temp2; if(m&1)//如果装入奇数个物品,左右个数相同,例如5个,左边就2个,右边两个,我们只需要枚举中间那一个即可 { temp1=m>>1; temp2=m>>1; } else//8个,我们左边3个,右边4个,中间1个,进行类似三分 { temp1=m/2-1; temp2=m/2; } priority_queue<int> p1;//左边 priority_queue<int> p2;//右边 int sum=0; for(int i=1;i<=n;i++)l[i]表示包括i在内前面temp1个物品的最小空间,因为我们必须尽可能留更多的空间给中间的那个 { p1.push(a[i].second); l[i]=l[i-1]+a[i].second; if(p1.size()>temp1) l[i]-=p1.top(),p1.pop(); } for(int i=n;i;i--)//r[i]表示包括i在内后面temp2个物品的最小空间,因为我们必须尽可能留更多的空间给中间的那个
{ p2.push(a[i].second); r[i]=r[i+1]+a[i].second; if(p2.size()>temp2) r[i]-=p2.top(),p2.pop(); } if(m&1) { int ans=0; for(int i=temp1+1;i<=n-temp2;i++)//奇数的时候我们只需要枚举中间那个的位置即可 { if(l[i-1]+r[i+1]+a[i].second<=v) ans=a[i].first; } cout<<ans<<"\n"; } else//否则我们需要枚举后面那部分的位置,用二分,在满足的条件下尽量往右靠,因为这个是按照价值从小到大排序的 { int ans=0; for(int i=temp1+1;i<=n-temp2;i++) { int pos=0; int ln=i+1,rn=n-temp2+1; while(ln<=rn) { int mid=(ln+rn)>>1; if(l[i-1]+a[i].second+r[mid]<=v) pos=mid,ln=mid+1; else rn=mid-1; } if(pos) ans=max(ans,a[i].first+a[pos].first); } cout<<ans/2<<endl; } }
也是第一次遇到这种题目,看大佬思想都用优先队列然后二分求,记住吧。

浙公网安备 33010602011771号