题目来源:http://codeforces.com/problemset/problem/801/C
刚看到题目的时候就想着排序贪心做,但做到时间时,发现可以二分找时间,结果二分(也得注意一下细节)(写代码的时候务必静心!)和贪心都没写出来,感觉二分做的比较正,贪心也是思维(暴力......,因为n也不太大)的一种拓展吧....。附上二分和贪心的代码。
贪心:
如果排序完后,前i个在充电的情况下能够达到i+1个的时间,就把i+1加起来。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
double k,p;
struct A {
double a,b,t;
}c[100100];
bool cmp(struct A t1,struct A t2)
{
if(t1.t==t2.t)
return t1.a<t2.a;
else
return t1.t<t2.t;
}
int main()
{
int i,j;
cin>>n>>p;
double sum=0.0;
for(i=0;i<n;i++)
{
cin>>c[i].a>>c[i].b;
c[i].t=c[i].b/c[i].a;
sum+=c[i].a;
}
if(sum<=p)//每秒消耗的小于等于补充的因为换的时间题目说了忽略不计 毫无疑问
{
printf("-1");
return 0;
}
sort(c,c+n,cmp);//对时间进行排序,从小到大
double pow=c[0].t*p,dec=c[0].a,ans=0.0;
for(i=0;i<n-1;i++)
{
if(pow+(c[i+1].t-c[i].t)*p>(c[i+1].t-c[i].t)*dec)
{
pow+=(c[i+1].t-c[i].t)*(p-dec),dec+=c[i+1].a;
}
else
{
break;
}
}
ans=pow/(dec-p);//多余的能量除以消耗的能量等于延续的时间
ans+=c[i].t;//加初始的时间
printf("%.8f\n",ans);
return 0;
}
二分:
若运算完还有能量可以继续充电,则继续扩大时间,若小于并等于需要继续减小。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
double n,k,p;
struct A {
double a;
double b;
double v;
}c[100100];
double pd(double t)
{
int i,j;
double sum=p*t;
for(i=0;i<n;i++)
{
double temp=c[i].b-c[i].a*t;
if(temp<0)
sum+=temp;
}
return sum;
}
int main()
{
int i,j;
cin>>n>>p;
double sum=0.0;
for(i=0;i<n;i++)
{
cin>>c[i].a>>c[i].b;
sum+=c[i].a;
}
if(sum<=p)
{
printf("-1");
return 0;
}
double l=0,r=1e10,mid;
while(l+1e-4<=r)//小数的一般都带精确的值
{
mid=(l+r)/2;
if(pd(mid)>0)//等于0时的恰好
l=mid;
else
r=mid;
}
printf("%.8lf",mid);
return 0;
}