首次接触到了这种\(01\)分数规划类的问题。 http://codeforces.com/problemset/problem/489/E \(01\)分数规划,指的是两个数组\(a\)与\(b\),通过构造一个\(01\)序列\(s_i\)使得\[\frac{\sum a_i\times s_i}{\sum b_i\times s_i}\]
最大(或最小)。 首先我们假设我们找到了最值\(L\),使得\[\frac{\sum a_i\times s_i}{\sum b_i\times s_i}\leq L\]。 那么对于任意一个\(01\)序列\(s\),都有\[\sum a_i\times s_i-(\sum b_i\times s_i)\times L \leq 0\]
这样我们就可以二分\(L\),通过DP找到最小的\(\sum a_i\times s_i-(\sum b_i\times s_i)\times L\)与\(0\)进行比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include<bits/stdc++.h> using namespace std; int n,l; int x[1010]={}; int b[1010]={}; double dp[1010]={}; int pr[1010]={}; bool ff(double q) { dp[0]=0; for(int i=1;i<=n;i++) { dp[i]=2147483600.0; } for(int i=1;i<=n;i++) { for(int j=0;j<i;j++) { dp[i]=min(dp[i],dp[j]+sqrt(fabs(x[i]-x[j]-l))-b[i]*1.0*q); } } if(dp[n]>=0) return 0; else return 1; } void ans(double q) { int an[1010]={}; int u=0; dp[0]=0; for(int i=1;i<=n;i++) { dp[i]=2147483600.0; } for(int i=1;i<=n;i++) { for(int j=0;j<i;j++) { if(dp[j]+sqrt(fabs(x[i]-x[j]-l))-b[i]*1.0*q<dp[i]) { pr[i]=j; dp[i]=dp[j]+sqrt(fabs(x[i]-x[j]-l))-b[i]*1.0*q; } } } int p=n; while(p!=0) { an[++u]=p; p=pr[p]; } for(int i=u;i>=1;i--) printf("%d ",an[i]); } int main() { scanf("%d%d",&n,&l); for(int i=1;i<=n;i++) { scanf("%d%d",&x[i],&b[i]); } double z=0.0; double r=2147483600.0; int t=0; while(t<=100) { t++; double mid=(z+r)/2.0; if(ff(mid)) r=mid; else z=mid; } ans(z); return 0; }
|