zoukankan      html  css  js  c++  java
  • bzoj4753[JSOI2016]最佳团体

    题意:01分数规划,但可选的数字之间存在森林形的依赖关系(可以认为0号点是个虚根,因为并不能选).

    虽然有森林形的依赖关系,但还是可以套分数规划的思路,二分答案k,判断是否存在一个比值大于k的方案

    即是否存在一种选取方式使得sigma{fight[i],i is choosed}/sigma{cost[i],i is choosed}>=k

    移项,发现只需要sigma{fight[i]-cost[i]*k,i is choosed}>=0,也就是把每个点的权值设置成”战斗力-花费*比值”,判断是否存在一种满足依赖关系的选取方案使得选择的权值之和>=0,那么让权值之和尽量大判定最大值是否大于等于0即可.定义f[i][j]表示i为根的子树中选取j个点时的最大权值,用背包暴力转移,看似是O(n^3)的,但仔细分析发现复杂度是O(n^2)的,因为每次合并一棵子树时付出的代价是”已经合并的兄弟子树的大小之和”*”正在合并的这棵子树的大小”,实质上是树上每对节点在LCA处贡献时间复杂度,这一部分相当于bzoj4033.

    于是总体复杂度是O (log(ans)*N^2),n是2500,感觉很虚但是能跑过去…注意处理某棵子树如果选择那么子树的根节点必须选择,以及0号节点的处理.再有就是二分精度一定要调好.

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=2505;
    struct edge{
      int to,next;
    }lst[maxn];int first[maxn],len=1;
    void addedge(int a,int b){
      lst[len].to=b;lst[len].next=first[a];first[a]=len++;
    }
    int k,n;
    int cost[maxn],fight[maxn],prt[maxn],sz[maxn];
    double w[maxn];
    double f[maxn][maxn];
    void dfs(int x){
      sz[x]=1;
      for(int pt=first[x];pt;pt=lst[pt].next){
        dfs(lst[pt].to);
        sz[x]+=sz[lst[pt].to];
      }
    }
    void dp(int x){
      int tot=0;
      if(x)f[x][1]=w[x],tot=1;
      else f[x][0]=0;
      for(int pt=first[x];pt;pt=lst[pt].next){
        dp(lst[pt].to);tot+=sz[lst[pt].to];
        for(int i=tot;i>=0;--i){
          for(int j=0;j<=sz[lst[pt].to]&&j<=i;++j){
        f[x][i]=max(f[x][i],f[x][i-j]+f[lst[pt].to][j]);
          }
        }
      }
      
    }
    bool check(double ans){
      for(int i=1;i<=n;++i){
        w[i]=fight[i]-ans*cost[i];
      }
      memset(f,0xc2,sizeof(f));
      dp(0);//printf("%.3f
    ",f[2][1]);
      return f[0][k]>=0;
    }
    int main(){
      scanf("%d%d",&k,&n);
      for(int i=1;i<=n;++i){
        scanf("%d%d%d",&cost[i],&fight[i],&prt[i]);addedge(prt[i],i);
      }
      dfs(0);
      double l=0,r=1e4;
      while(r-l>1e-5){
        double mid=(l+r)/2;
        if(check(mid))l=mid;
        else r=mid;
      }
      printf("%.3f
    ",(r+l)/2);
      return 0;
    }
  • 相关阅读:
    FusionMap 检测融合基因
    嵌合体序列
    seqtk 的安装和使用
    cutadapt 的安装与使用
    C语言简单选择排序
    C语言冒泡排序
    Java实现的各种排序算法(包括冒泡,快排等)
    C++实现顺序计算输入表达式的值
    java多线程有几种实现方法?线程之间如何同步
    java中==与equal()方法的区别
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6399224.html
Copyright © 2011-2022 走看看