题解 P4377 【[USACO18OPEN]Talent Show】

wenge

2019-07-29 22:58:23

Solution

我看题解全都是01分数规划和贪心,很少有背包,所以发一个不需要01分数规划,直接套裸背包的做法。 记录$dp[i][j]$为考虑前$i$头牛,选的牛才艺值总和为$j$的最小重量。 则有 $$dp[i][j]=min(dp[i-1][j],dp[i-1][j-t[i]]+w[i])(j\geq t[i])$$ $$dp[i][j]=dp[i-1][j](j<t[i])$$ 边界条件:$dp[0][0]=0$,其余$dp[i][j]=\inf$ 这就是一个裸的背包了。答案就是$max(\frac {i}{dp[i]})(0\leq i\leq \sum t_i,dp[i]\geq W)$。 因为背包容量$m$至多是$\sum t_i\leq250000$,二维数组会MLE。所以直接滚动数组压掉一维就可以了。 时间复杂度$O(n*\sum t_i)=O(n^2*max\ t_i)$,可以通过本题。 AC代码: ```cpp //#pragma GCC optimize(2) #include <iostream> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <cstdio> #include <queue> #include <iomanip> #include <vector> //int mod=1000000007; using namespace std; typedef long long ll; //typedef __int128 lll; #define clr(a,b) memset(a,b,sizeof(a)); ll w[255],t[255]; ll dp[250005]; ll n,m,k,ans; int main(){ //ios::sync_with_stdio(false); //cin.tie(0); cin>>n>>k; for(int i=1;i<=n;i++){ cin>>w[i]>>t[i]; m+=t[i]; } clr(dp,0x7f); dp[0]=0; for(int i=1;i<=n;i++){ for(int j=m;j>=0;j--){ if(j>=t[i])dp[j]=min(dp[j],dp[j-t[i]]+w[i]); } } double ans=0; for(int i=0;i<=m;i++){ if(dp[i]>0&&dp[i]>=k)ans=max(i*1000.0/dp[i],ans); //if(dp[i]>0&&dp[i]>=k)cout<<i<<" "<<i*1000.0/dp[i]<<"\n"; } ll ans1=ans; cout<<ans1; return 0; } ```