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;
    }
  • 相关阅读:
    C++学生成绩管理系统
    蓝桥杯算法训练 最大最小公倍数
    蓝桥杯基础练习 完美的代价
    vim编辑器的使用技巧
    C语言中static关键字的用法
    在linux环境下编译运行OpenCV程序的两种方法
    Linux中gcc编译器的用法
    浅谈Java中的hashcode方法
    读CopyOnWriteArrayList有感
    徐汉彬:Web系统大规模并发——电商秒杀与抢购(技术实现)
  • 原文地址:https://www.cnblogs.com/Gloid/p/9928584.html
Copyright © 2011-2022 走看看