[Usaco2018 Open]Talent Show
Description
FarmerJohn要帶著他的N頭奶牛,方便起見編號為1…N,到農業展覽會上去,參加每年的達牛秀!他的第i頭奶牛重量為wi,才藝水平為ti,兩者都是整數。在到達時,FarmerJohn就被今年達牛秀的新規則嚇到了:(一)參加比賽的一組奶牛必須總重量至少為W(這是為了確保是強大的隊伍在比賽,而不僅是強大的某頭奶牛),並且(二)總才藝值與總重量的比值最大的一組獲得勝利。FJ註意到他的所有奶牛的總重量不小於W,所以他能夠派出符合規則(一)的隊伍。幫助他確定這樣的隊伍中能夠達到的最佳的才藝與重量的比值。
Input
輸入的第一行包含N和W。下面N行,每行用兩個整數wi和ti描述了一頭奶牛。
1≤N≤250
1≤W≤1000
1≤wi≤10^6
1≤ti≤10^3
Output
請求出Farmer用一組總重量最少為W的奶牛最大可能達到的總才藝值與總重量的比值。
如果你的答案是A,輸出1000A向下取整的值,以使得輸出是整數(當問題中的數不是一個整數的時候,向下取整操作在向下舍入到整數的時候去除所有小數部分)。
Sample Input
3 15
20 21
10 11
30 31
Sample Output
1066
HINT
在這個例子中,總體來看最佳的才藝與重量的比值應該是僅用一頭才藝值為11、重量為10的奶牛,但是由於我們需要至少15單位的重量,最優解最終為使用這頭奶牛加上才藝值為21、重量為20的奶牛。這樣的話才藝與重量的比值為(11+21)/(10+20)=32/30=1.0666666...,乘以1000向下取整之後得到1066。
首先想到dp,設f[i]代表才藝值和為i的奶牛重量,讓f[i]越小越好。這樣顯然是錯的,不過bzoj和洛谷就這麽過掉了。。。(數據真水)
放上錯誤dp代碼
/*program from Wolfycz*/ #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define inf 0x7f7f7f7f using namespace std; typedef long long ll; typedef unsigned int ui; typedef unsigned long long ull; inline int read(){ int x=0,f=1;char ch=getchar(); for (;ch<‘0‘||ch>‘9‘;ch=getchar()) if (ch==‘-‘) f=-1; for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=(x<<1)+(x<<3)+ch-‘0‘; return x*f; } inline void print(int x){ if (x>=10) print(x/10); putchar(x%10+‘0‘); } const int N=2.5e2,M=1e3; int f[N*M+10]; int main(){ int n=read(),W=read(); memset(f,127,sizeof(f)); f[0]=0; for (int i=1;i<=n;i++){ int x=read(),y=read(); for (int j=N*M;j>=y;j--) f[j]=min(f[j],f[j-y]+x); } int Ans=0; for (int i=1;i<=N*M;i++) if (f[i]>=W) Ans=max(Ans,i*1000/f[i]); printf("%d\n",Ans); return 0; }
後面想了想隨手造了個數據把自己hack了。。。
3 10
7 10
2 10
9 10
stdout:1818
myout:1666
那怎麽改呢?首先我們知道這題要求$\dfrac{\sum t[i]}{\sum w[i]}$最大,我們轉化一下得到$\sum(t[i]-w[i]\times x)$,然後x這玩意是可以二分的,直接01背包判可行性即可
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<‘0‘||ch>‘9‘;ch=getchar()) if (ch==‘-‘) f=-1;
for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=(x<<1)+(x<<3)+ch-‘0‘;
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+‘0‘);
}
const int N=2.5e2,M=1e3;
int f[N*M+10],w[N+10],v[N+10],n,W;
bool check(int limit){
memset(f,128,sizeof(f));
f[0]=0;
for (int i=1;i<=n;i++)
for (int j=W;~j;j--)
if (f[j]!=-inf)
f[min(W,j+w[i])]=max(1ll*f[min(W,j+w[i])],f[j]+v[i]-1ll*w[i]*limit);
return f[W]>=0;
}
int main(){
n=read(),W=read();
int l=1,r=0,Ans=0;
for (int i=1;i<=n;i++) w[i]=read(),r+=v[i]=read()*1000;
while (l<=r){
int mid=(l+r)>>1;
if (check(mid)) Ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",Ans);
return 0;
}
[Usaco2018 Open]Talent Show