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 }