1. 程式人生 > >BZOJ4753:[JSOI2016]最佳團體——題解

BZOJ4753:[JSOI2016]最佳團體——題解

訪問 add read isdigit esp getc lib pro 性價比

https://www.lydsy.com/JudgeOnline/problem.php?id=4753

JSOI信息學代表隊一共有N名候選人,這些候選人從1到N編號。方便起見,JYY的編號是0號。每個候選人都由一位 編號比他小的候選人Ri推薦。如果Ri=0則說明這個候選人是JYY自己看上的。為了保證團隊的和諧,JYY需要保證, 如果招募了候選人i,那麽候選人Ri"也一定需要在團隊中。當然了,JYY自己總是在團隊裏的。每一個候選人都有 一個戰鬥值Pi",也有一個招募費用Si"。JYY希望招募K個候選人(JYY自己不算),組成一個性價比最高的團隊。 也就是,這K個被JYY選擇的候選人的總戰鬥值與總招募總費用的比值最大。

01分數規劃裸題,二分答案w,每個點點權為p[i]-w*s[i],判斷最大值是否>0即可。

顯然是樹型背包問題,由於看不懂什麽神奇的刷表法,我還是寫的復雜度我不會證的dfs。

於是我人傻自帶大常數硬生生把傻逼題寫成神題……

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include
<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; typedef double dl; const int INF=1e7; const int N=2505; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch==-;ch=getchar();} while
(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int to,nxt; }e[N*2]; int cnt,k,n,s[N],p[N],head[N],sz[N]; dl dp[N][N],w[N]; inline int add(int u,int v){ e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt; } void dfs(int u){ for(int i=0;i<=k;i++)dp[u][i]=-INF; if(u)dp[u][1]=w[u],sz[u]=1; else dp[u][0]=0,sz[u]=0; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to;dfs(v); int len=u?1:0; for(int j=min(k,sz[u]);j>=len;j--) for(int l=1;l<=min(k-j,sz[v]);l++) dp[u][j+l]=max(dp[u][j+l],dp[u][j]+dp[v][l]); sz[u]+=sz[v]; } } bool pan(dl W){ for(int i=1;i<=n;i++)w[i]=(dl)p[i]-W*s[i]; dfs(0); return dp[0][k]>0; } int main(){ k=read(),n=read(); for(int i=1;i<=n;i++){ s[i]=read(),p[i]=read(); add(read(),i); } dl l=0,r=1e4; for(int i=1;i<=30;i++){ dl mid=(l+r)/2; if(pan(mid))l=mid; else r=mid; } printf("%.3lf\n",l); return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ4753:[JSOI2016]最佳團體——題解