BZOJ_4753_[Jsoi2016]最佳團體_樹形背包+01分數規劃
阿新 • • 發佈:2018-05-26
AC 也有 clas ont 二分 人的 amp strong string
1000 1 0
1 1000 1
BZOJ_4753_[Jsoi2016]最佳團體_樹形背包+01分數規劃
Description
JSOI信息學代表隊一共有N名候選人,這些候選人從1到N編號。方便起見,JYY的編號是0號。每個候選人都由一位 編號比他小的候選人Ri推薦。如果Ri=0則說明這個候選人是JYY自己看上的。為了保證團隊的和諧,JYY需要保證, 如果招募了候選人i,那麽候選人Ri"也一定需要在團隊中。當然了,JYY自己總是在團隊裏的。每一個候選人都有 一個戰鬥值Pi",也有一個招募費用Si"。JYY希望招募K個候選人(JYY自己不算),組成一個性價比最高的團隊。 也就是,這K個被JYY選擇的候選人的總戰鬥值與總招募總費用的比值最大。Input
輸入一行包含兩個正整數K和N。 接下來N行,其中第i行包含3個整數Si,Pi,Ri表示候選人i的招募費用,戰鬥值和推薦人編號。 對於100%的數據滿足1≤K≤N≤2500,0<"Si,Pi"≤10^4,0≤Ri<iOutput
輸出一行一個實數,表示最佳比值。答案保留三位小數。Sample Input
1 21000 1 0
1 1000 1
Sample Output
0.001
二分答案x,令t[i]=P[i]-x*S[i]。
然後建立源點S,跑個樹形背包求f[S][K+1]是否大於0即可。
代碼:
#include <cstdio> #include <string.h> #include <algorithm> using namespace std; typedef double f2; #define N 2550 #define S (n+1) #define eps 1e-6 #define inf 1000000000 int head[N],to[N<<1],nxt[N<<1],cnt,n,K,A[N],B[N],C[N],siz[N]; f2 t[N],g[N],f[N][N]; inline void add(int u,int v) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; } void dfs(int x) { siz[x]=1;int i,j,k; f[x][1]=t[x]; for(k=head[x];k;k=nxt[k]) { dfs(to[k]); for(i=1;i<=siz[x]+siz[to[k]];i++) g[i]=f[x][i]; for(i=1;i<=siz[x];i++) if(f[x][i]>-inf) { for(j=1;j<=siz[to[k]];j++) if(f[to[k]][j]>-inf) { g[i+j]=max(g[i+j],f[x][i]+f[to[k]][j]); } } for(i=1;i<=siz[x]+siz[to[k]];i++) f[x][i]=g[i]; siz[x]+=siz[to[k]]; } } bool check(f2 x) { int i,j; for(i=0;i<=n;i++) t[i]=B[i]-x*A[i]; t[S]=0; for(i=1;i<=S;i++) { for(j=1;j<=K+1;j++) { f[i][j]=-inf; } } dfs(S); return f[S][K+1]>eps; } int main() { //freopen("sales.in","r",stdin); //freopen("sales.out","w",stdout); scanf("%d%d",&K,&n); int i; f2 sum=0; for(i=1;i<=n;i++) { scanf("%d%d%d",&A[i],&B[i],&C[i]); if(!C[i]) C[i]=S; add(C[i],i); sum+=A[i]; } f2 l=0,r=10000; while(r-l>eps) { f2 mid=(l+r)/2; if(check(mid)) l=mid; else r=mid; } printf("%.3f\n",l); }
BZOJ_4753_[Jsoi2016]最佳團體_樹形背包+01分數規劃