zoukankan      html  css  js  c++  java
  • BZOJ4753 JSOI2016最佳团体(分数规划+树形dp)

      看到比值先二分答案。于是转化成一个非常裸的树形背包。直接暴力背包的话复杂度就是O(n2),因为相当于在lca处枚举每个点对。这里使用一种更通用的dfs序优化树形背包写法。https://www.cnblogs.com/zzqsblog/p/5537440.html 即设f[i][j]为在dfs序第i~n个点中选j个(所选点不一定连通)的最大权值,考虑是否选择第i个点,如果不选显然f[i][j]=f[i+size][j],否则f[i][j]=f[i+1][j-1]+v[i]。注意dp过程中虽然没有保证所选点都连通,但一旦考虑完一棵子树,子树内部就一定构成连通块了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 2510
    char getc(){char c=getchar();while (c==10||c==13||c==32) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    const double eps=1E-5;
    int n,m,w[N],v[N],fa[N],p[N],id[N],size[N],cnt=-1,t;
    double a[N],f[N][N];
    struct data{int to,nxt;
    }edge[N<<1];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void dfs(int k)
    {
        id[++cnt]=k;size[k]=1;
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=fa[k]) dfs(edge[i].to),size[k]+=size[edge[i].to];
    }
    bool check()
    {
        for (int i=0;i<=n+1;i++)
            for (int j=1;j<=m+1;j++)
            f[i][j]=-100000000;
        for (int i=n;i>=0;i--)
            for (int j=1;j<=m+1;j++)
            f[i][j]=max(f[i+1][j-1]+a[id[i]],f[i+size[id[i]]][j]);
        return f[0][m+1]>=0;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4753.in","r",stdin);
        freopen("bzoj4753.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        m=read(),n=read();
        double l=0,r=0,ans=0;
        for (int i=1;i<=n;i++)
        {
            w[i]=read(),r+=v[i]=read(),fa[i]=read();
            addedge(fa[i],i);
        }
        dfs(0);
        while (l+eps<r)
        {
            double mid=(l+r)/2;
            for (int i=1;i<=n;i++) a[i]=v[i]-w[i]*mid;
            if (check()) ans=mid,l=mid+eps;
            else r=mid-eps;
        }
        printf("%.3f",ans);
        return 0;
    }
  • 相关阅读:
    cf D. Vessels
    cf C. Hamburgers
    zoj 3758 Singles' Day
    zoj 3777 Problem Arrangement
    zoj 3778 Talented Chef
    hdu 5087 Revenge of LIS II
    zoj 3785 What day is that day?
    zoj 3787 Access System
    判断给定图是否存在合法拓扑排序
    树-堆结构练习——合并果子之哈夫曼树
  • 原文地址:https://www.cnblogs.com/Gloid/p/9928584.html
Copyright © 2011-2022 走看看