Talent Show (二分+DP)

                                              Talent Show

                                                                        时间限制: 1 Sec  内存限制: 128 MB
                                                                                 提交: 101  解决: 39
                                                                        [提交] [状态] [讨论版] [命题人:admin

题目描述

Farmer John is bringing his N cows, conveniently numbered 1…N, to the county fair, to compete in the annual bovine talent show! His ith cow has a weight wiwi and talent level ti, both integers.
Upon arrival, Farmer John is quite surprised by the new rules for this year's talent show:

(i) A group of cows of total weight at least W must be entered into the show (in order to ensure strong teams of cows are competing, not just strong individuals), and

(ii) The group with the largest ratio of total talent to total weight shall win.

FJ observes that all of his cows together have weight at least W, so he should be able to enter a team satisfying (i). Help him determine the optimal ratio of talent to weight he can achieve for any such team.

输入

The first line of input contains N (1≤N≤250) and W (1≤W≤1000). The next N lines each describe a cow using two integers wi (1≤wi≤106) and ti (1≤ti≤103).

输出

Please determine the largest possible ratio of total talent over total weight Farmer John can achieve using a group of cows of total weight at least W. If your answer is A, please print out the floor of 1000A in order to keep the output integer-valued (the floor operation discards any fractional part by rounding down to an integer, if the number in question is not already an integer).

样例输入

3 15
20 21
10 11
30 31

样例输出

1066

提示

In this example, the best talent-to-weight ratio overall would be to use just the single cow with talent 11 and weight 10, but since we need at least 15 units of weight, the optimal solution ends up being to use this cow plus the cow with talent 21 and weight 20. This gives a talent-to-weight ratio of (11+21)/(10+20) = 32/30 = 1.0666666..., which when multiplied by 1000 and floored gives 1066.

                                                                                          [提交]   [状态]

题意:有n件物品,重量分别是wi,价值是ti,要求在满足wi的和大于等于W的情况下,能得到的最大  ti和/wi 和的比,结果向下取整,然后乘1000倍。

观察ti和/wi和,此处用sum代替sigma.设sum(ti)/sum(wi) = x.则有sum(ti) = sum(wi)*x. 进一步得出sum(ti)-sum(wi)*x = 0.展开后利用加法交换律得到sum(ti-wi*x) = 0. 此时发现ti,wi可以枚举,只留下x不确定,然后结果要求是0。考虑二分x,若加起来的和>0,说明x的值小了,若加起来的和<0,说明x大了,然后考虑到和的问题。

求和的问题明显可以看作是0-1背包问题,即dp[i]表示重量为i的情况下,可获得的最大值。然后发现此时的背包容量可以是特别大,而没有具体值,调试许久,发现将重量大于W之后的值都当作W看待时,结果符合答案。对于dp[W],若他大于等于0,说明mid小了,否则说明mid大了。

再者0-1背包的过程中,由于背包的容量没有上限,所以背包的权值可以是在0到W+wi,所以二维dp维护的过程中可以将j-wi变成j+wi。,然后再进行背包。

最后得到结果,为了方便计算,可以在开始的时候就将ti*1000,即被除数扩大1000倍,这样结果自然扩大了1000倍,用longlong计算,解决了向下取整的问题。

出自:ugly

#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int N = 1e5+5;
const ll mod = 1e9+7;
const ll INF = 0x3f3f3f3f;
 
ll t[N],w[N];
 
ll n,W,dp[N];
 
int judge(int mid)
{
 
    int i,j,k;
 
    memset(dp,-INF,sizeof(dp));
 
    dp[0] = 0;
 
    bool flag = false;
 
    for(i = 1;i <= n;i++)
    {
 
        for(j = W;j >= 0;j--)
 
        {
 
            int tt = min(W,j+w[i]);          //容量无限大,只需关注W 
 
            dp[tt] = max(dp[tt],dp[j]+t[i]-w[i]*mid);
 
        }
 
    }
 
    if(dp[W] >= 0)
 
    return 1;
 
    return 0;
 
}
 
 
int main()
 
{
 
    ll i,j,k;
    scanf("%lld",&n);
    scanf("%lld",&W);
 
    for(i = 1;i <= n;i++)
    {
 
        scanf("%lld",&w[i]);
        scanf("%lld",&t[i]);
        t[i] = t[i]*1000;  //被除数*1000,直接取整 
 
    }
 
    ll l = 0,r = 100005,mid;
 
    while(l <= r)
 
    {
 
        mid = (l+r)/2;
 
        if(judge(mid))
 
        l = mid+1;
 
        else
 
        r = mid-1;
 
    }
 
    printf("%lld\n",r);
 
}

猜你喜欢

转载自blog.csdn.net/qq_41021816/article/details/81166829