题目一般是这样的:有N个物品,每个物品重c[i],价值v[i],从中选K个,求
其中use[i]是0 或 1,表示选或不选这件物品
设最终答案为
res
r
e
s
即:
化简一哈:
∑(res∗c[i]−v[i])∗use[i])=0 ∑ ( r e s ∗ c [ i ] − v [ i ] ) ∗ u s e [ i ] ) = 0
但是我们不知道res是多少,所以就设为 x 好啦~
设一大坨为
f(x)
f
(
x
)
即:
f(x)=∑(res∗c[i]−v[i])∗use[i])
f
(
x
)
=
∑
(
r
e
s
∗
c
[
i
]
−
v
[
i
]
)
∗
u
s
e
[
i
]
)
x
x
不一样,就不一样,并且当
x
x
越接近最终的 ,
f(x)
f
(
x
)
就越接近0对吧
于是我们就来猜
x
x
,运气好的话,刚好猜到一个使得
f(x)=0
f
(
x
)
=
0
But
However
Nevertheless
Whereas
Yet
我是一个喜欢靠实力的大帅比~而不喜欢靠运气0.0
所以我们发现
f(x)
f
(
x
)
是与
x
x
有关的,
我的这个是增函数,
x
x
增大,就增大
所以,
当我们得到
f(x)>0
f
(
x
)
>
0
时,那就想要把
x
x
减小
反之,时,那就要把
x
x
弄大
所以,就是二分嘛
#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 来算的 f(x) f ( x )
这计算的与上一次计算的会越来越近,当他们的差小于一定值时,就认为相等,就是答案了
//迭代
#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;
}
}