题目一般是这样的:有N个物品,每个物品重c[i],价值v[i],从中选K个,求
其中use[i]是0 或 1,表示选或不选这件物品
设最终答案为
即:
化简一哈:
但是我们不知道res是多少,所以就设为 x 好啦~
设一大坨为
即:
不一样, 就不一样,并且当 越接近最终的 , 就越接近0对吧
于是我们就来猜 ,运气好的话,刚好猜到一个 使得
But
However
Nevertheless
Whereas
Yet
我是一个喜欢靠实力的大帅比~而不喜欢靠运气0.0
所以我们发现 是与 有关的,
我的这个 是增函数, 增大, 就增大
所以,
当我们得到 时,那就想要把 减小
反之, 时,那就要把 弄大
所以,就是二分嘛
#include"iostream"
#include"algorithm"
#include"iomanip"
using namespace std;
const int maxn=1e5+5;
const double eps=1e-6;
int c[maxn],v[maxn];
struct AAA
{
double f;
int id;/*这个id是用来打印出来到底是选了哪K个*/
bool operator<(const AAA &a)const
{
return f<a.f;
}
};
AAA use[maxn];
int main()
{
cout.setf(ios::fixed);
int T;
cin>>T;
int N,K;
while(T--)
{
cin>>N>>K;
for(int i=0;i<N;i++)cin>>c[i]>>v[i];
double L=-100,R=100;/*这里的边界要取得合适,上界要大于答案,下界要小于答案*/
double x,fx;
while(R-L>eps)
{
x=(L+R)/2.0;
for(int i=0;i<N;i++)
{
use[i].f=1.0*x*c[i]-1.0*v[i];
use[i].id=i+1;
}
sort(use,use+N);
fx=0;
for(int i=0;i<K;i++)fx+=use[i].f;/*因为要最大的嘛,就选出最大的K个*/
if(fx>0)R=x;
else L=x;
}
cout<<setprecision(2)<<x<<endl;
}
}
第二种方法:
迭代法:
如果我们选的那K个物品的 就是最终的res的话,那肯定是等于我们用这K个得到的average 来算的
这计算的与上一次计算的会越来越近,当他们的差小于一定值时,就认为相等,就是答案了
//迭代
#include"iostream"
#include"algorithm"
#include"iomanip"
using namespace std;
const int maxn=1e5+5;
const double eps=1e-6;
int c[maxn],v[maxn];
struct AAA
{
double c,v,f;
bool operator<(const AAA &a)const
{
return f<a.f;
}
};
AAA use[maxn];
int main()
{
cout.setf(ios::fixed);
int T;
cin>>T;
int N,K;
while(T--)
{
cin>>N>>K;
for(int i=0;i<N;i++)cin>>use[i].c>>use[i].v;
/*先随便猜一个答案*/
double res=rand();
double res_calc=res+1;/*这样是为了进循环*/
while(fabs(res_calc-res)>eps)
{
res=res_calc;
for(int i=0;i<N;i++)use[i].f=res*use[i].c-use[i].v;
sort(use,use+N);
double c_use=0,v_use=0;
for(int i=0;i<K;i++)
{
c_use+=use[i].c;
v_use+=use[i].v;
}
res_calc=1.0*v_use/c_use;/*res_calc就是根据res选的这K个计算而来的*/
}
cout<<setprecision(2)<<res<<endl;
}
}