zoukankan      html  css  js  c++  java
  • bzoj 5281 Talent Show —— 01分数规划+背包

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5281

    二分一个答案比值,因为最后要*1000,不如先把 v[] *1000,就可以二分整数;

    枚举 mid ,如果 mid 小于等于 ans ,则 ∑v[i] - mid * ∑w[i] >= 0,可以继续往大调整,为了使答案最大,背包找一下使这个值最大的组合,看看能否 >=0;

    数组开 1000 即可... 把 w 大于 1000 的直接当做最大的 w 。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define mid ((l+r)>>1)
    using namespace std;
    typedef long long ll;
    int const xn=255;
    int n,m,ans,w[xn];
    ll f[1005],tmp[xn],v[xn];
    int rd()
    {
        int ret=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
        while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
        return f?ret:-ret;
    }
    bool ck(int k)
    {
        for(int i=1;i<=n;i++)tmp[i]=v[i]-(ll)w[i]*k;
        memset(f,-2,sizeof f);//
        f[0]=0;
        for(int i=1;i<=n;i++)
            for(int j=m;j>=0;j--)
                f[min(m,j+w[i])]=max(f[min(m,j+w[i])],f[j]+tmp[i]);
        return f[m]>=0;
    }
    int main()
    {
        n=rd(); m=rd();
        for(int i=1;i<=n;i++)w[i]=rd(),v[i]=rd()*1000;
        int l=1,r=1e9;
        while(l<=r)
        {
            if(ck(mid))ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    【VectorDemo】
    【列表迭代器:添加元素】
    【列表迭代器】
    【迭代器】
    【LinkedList】
    【list 集合的使用】
    【CollectionDemo2】
    【CollectionDemo1】
    【集合和数组的区别?】
    【到底使用那种集合?】
  • 原文地址:https://www.cnblogs.com/Zinn/p/9707872.html
Copyright © 2011-2022 走看看