bzoj5281/luogu4377 Talent Show (01分数规划+背包dp)

就是01分数规划的思路,只不过当把w[i]-r*t[i]>0的选完以后如果w值还没达到要求,那就再01背包dp一下就好了(dp时w值>W的时候就存在W里就不会爆内存了)。

(跑得很慢..大概是二分的姿势有问题...)

(貌似还有直接dp的做法?不会)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<vector>
 6 #include<queue>
 7 #include<set>
 8 #include<ctime>
 9 #define pa pair<double,int>
10 #define LL long long
11 using namespace std;
12 const int maxn=260,maxm=1010;
13 
14 LL rd(){
15     LL x=0;char c=getchar();int neg=1;
16     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
17     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
18     return x*neg;
19 }
20 
21 int N,W,w[maxn],t[maxn];double f[maxn][maxm];
22 pa x[maxn];
23 
24 bool judge(double r){
25     for(int i=1;i<=N;i++) x[i]=make_pair(t[i]-r*w[i],i);
26     sort(x+1,x+N+1);
27     int sw=0,mm=N;double sr=0,mr=-123456789;
28     for(int i=N;i&&x[i].first>=0;mm=--i){
29         sw+=w[x[i].second];sr+=x[i].first;
30     }
31     if(sw>=W) return 1;
32     
33     f[0][0]=0;for(int j=1;j<=W-sw;j++) f[0][j]=-123456789;
34     for(int i=0;i<mm;i++){
35         for(int j=0;j<=W-sw;j++) f[i+1][j]=f[i][j];
36         for(int j=0;j<W-sw;j++){
37             f[i+1][min(W-sw,j+w[x[i+1].second])]=\
38             max(f[i+1][min(W-sw,j+w[x[i+1].second])],f[i][j]+x[i+1].first);
39         }
40     }
41     for(int i=1;i<=mm;i++) mr=max(mr,f[i][W-sw]);
42     return mr+sr>=0;
43 }
44 
45 int main(){
46     int i,j,k;
47     N=rd(),W=rd();
48     for(i=1,j=0;i<=N;i++) w[i]=rd(),t[i]=rd();
49     double l=0,r=2.5e7;
50     while(r-l>1e-5){
51         double m=(l+r)/2;
52         if(judge(m)) l=m;
53         else r=m-1e-5;
54     }printf("%d\n",(int)(l*1000));
55     return 0;
56 }

 

posted @ 2018-09-03 22:16  Ressed  阅读(212)  评论(0编辑  收藏  举报