zoukankan      html  css  js  c++  java
  • Luogu P4322 [JSOI2016]最佳团体(0/1分数规划)

    gate

    用时:写代码20min,debug+调emacs+卡常60min
    因为就是想找个0/1分数规划题,直接标签搜索的,所以没有思考时间...

    做2019各省省选的时候看到某个ac自动机+dp+0/1分数规划,想起来好像还没写过0/1分数规划...找个模板写一下。

    (0/1)分数规划

    有若干个元素,每个元素有(a,b)两个属性,选出其中一些元素,求 (max(frac{sum a}{sum b}))
    显然答案具有可二分性。设这个最大值为(mid),则对于每个元素,可以把原式转化为:

    [frac{sum a}{sum b} ge mid ]

    [sum a ge sum b imes mid ]

    [sum a - sum b imes mid ge 0 ]

    对于每个元素,设它的权值为(a[i]-b[i] imes mid),然后就可以转化为一般的(dp)或者其他类型的问题了。


    对于这道题,套路一下,设每个点的价值为(p[i]-s[i] imes mid),费用为(1),做树上背包即可。

    [f[u][i] = max(f[u][i-j] + f[v][j] ]

    注意

    • (0)必须选但不算人数,所以总容量(k++)
    • 父亲节点必须选,所以(i)的大小为((1,k))(j)的大小为((0,i-1))
    • 可能出现负数,一开始(0)以外的容量全赋为(-INF)

    卡常

    一开始(TLE 50),改了半天(TLE 90),我是傻逼,还是(O2)

    • 记录子树大小(siz[u]),上限改为(min(siz[u],k))能减少很多无意义计算,会快很多。(v)同理。
    • 数组不能太大,(eps)不能太小,别用(memset())...

    (code)

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define Mogeko qwq
    using namespace std;
    
    const int maxn = 2505;
    const int INF = 0x3f3f3f3f;
    const int R = 1e4;
    const double eps = 1e-4;
    
    int m,n,j,cnt;
    int head[maxn],to[maxn],nxt[maxn],siz[maxn];
    double s[maxn],p[maxn],f[maxn][maxn];
    double l,r,mid;
    
    int read(){
        int x = 0,f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){
            if(ch == '-') f = -1;
            ch = getchar();
        }
        while('0' <= ch && ch <= '9'){
            x = x*10 + ch-'0';
            ch = getchar();
        }
        return x*f;
    }
    
    void add(int x,int y){
        to[++cnt] = y;
        nxt[cnt] = head[x];
        head[x] = cnt;
    }
    
    void dfs(int u){
        //p/s=mid,p=s*mid,p-s*mid=0
        f[u][1] = p[u]-s[u]*mid;
        siz[u] = 1;
        for(int i = head[u];i;i = nxt[i]){
            int v = to[i];
            dfs(v);
            siz[u] += siz[v];
            for(int j = min(siz[u],m);j >= 1;j--)
                for(int k = 0;k <= min(siz[v],j-1);k++)   
                    f[u][j] = max(f[u][j],f[u][j-k] + f[v][k]);
        }
    }
    
    bool check(){
        for(int i = 0;i <= n;i++)
            for(int j = 1;j <= m;j++)
                f[i][j] = -INF;
        dfs(0);
        return f[0][m] >= 0;
    }
    
    int main(){
        m = read(),n = read();
        m++;
        for(int i = 1;i <= n;i++){
            s[i] = read(),p[i] = read();
            add(read(),i);
        }
        l = 0,r = R;
        while(r-l >= eps){
            mid = (l+r)*0.5;
            if(check()) l = mid;
            else r = mid;
        }
        printf("%.3lf
    ",l);
        return 0;
    }
    
    
  • 相关阅读:
    堆排序
    阿里云
    ubuntu下编译内核模块
    字节对齐
    线段树
    c++虚函数表解析
    电面
    sql server数据库定时自动备份
    [hiho1584]Bounce
    五彩斑斓的世界
  • 原文地址:https://www.cnblogs.com/mogeko/p/13180432.html
Copyright © 2011-2022 走看看