BZOJ4753 [Jsoi2016]最佳团体(01分数规划+树形背包)

原题

挂个链接BZOJ

Solution

分析:

这道题目显然直接01分数规划,然后树形DPcheck就好了。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<queue>
#include<algorithm>
#define ll long long
#define re register
using namespace std;
inline int gi(){
  int sum=0,f=1;char ch=getchar();
  while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
  while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
  return f*sum;
}
inline ll gl(){
  ll sum=0,f=1;char ch=getchar();
  while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
  while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
  return f*sum;
}
const double eps=1e-4;
const int maxn=3010;
int cnt,to[maxn<<1],front[maxn],nxt[maxn<<1];
void Add(int u,int v){
  to[++cnt]=v;nxt[cnt]=front[u];front[u]=cnt;
}
int n,k,siz[maxn],p[maxn],s[maxn];
double dp[maxn][maxn],tmp[maxn],v[maxn];
void merge(int u,int v){
  for(re int i=0;i<=k+1;i++)tmp[i]=-1e18;
  for(re int i=1;i<=siz[u] && i<=k+1;i++)
    for(re int j=1;j<=min(k+1-i,siz[v]);j++)
      tmp[i+j]=max(tmp[i+j],dp[u][i]+dp[v][j]);
  for(re int i=0;i<=k+1;i++)dp[u][i]=max(dp[u][i],tmp[i]);    
}
void dfs(int u){
  siz[u]=1;dp[u][1]=v[u];
  for(re int i=front[u];i;i=nxt[i]){
    int v=to[i];
    dfs(v);merge(u,v);
    siz[u]+=siz[v];
  }
}
bool check(double mid){
  for(re int i=1;i<=n;i++)v[i]=p[i]-s[i]*mid;
  memset(siz,0,sizeof(siz));
  dfs(0);
  return dp[0][k+1]>=0;
}
int main(){
  k=gi();n=gi();
  for(re int i=1;i<=n;i++){
    s[i]=gi(),p[i]=gi();int r=gi();
    Add(r,i);
  }
  double l=0,r=1000;
  while(r-l>eps){
    double mid=(l+r)/2;
    for(re int i=0;i<=n;i++)
      for(re int j=0;j<=k+1;j++)
    dp[i][j]=-1e18;
    if(check(mid))l=mid;
    else r=mid;
  }
  printf("%.3lf\n",l);
  return 0;
}
posted @ 2018-10-10 22:13  cj_gjh  阅读(92)  评论(0编辑  收藏  举报