bzoj 4753 最佳團體
阿新 • • 發佈:2018-11-27
轉化 using space dfs 答案 for ack char 滿足 自己不算),組成一個性價比最高的團隊。也就是,這\(K\)個被\(JYY\)選擇的候選人的總戰鬥值與總招募總費用的比值最大。
Written with StackEdit.
Description
\(JSOI\)信息學代表隊一共有N名候選人,這些候選人從\(1\)到\(N\)編號。方便起見,\(JYY\)的編號是\(0\)號。每個候選人都由一位編號比他小的候選人\(R_i\)推薦。如果\(R_i=0\)則說明這個候選人是\(JYY\)自己看上的。為了保證團隊的和諧,\(JYY\)需要保證,如果招募了候選人\(i\),那麽候選人\(R_i\)"也一定需要在團隊中。當然了,\(JYY\)自己總是在團隊裏的。每一個候選人都有一個戰鬥值P\(_i\)",也有一個招募費用\(S_i\)"。\(JYY\)希望招募\(K\)個候選人(\(JYY\)
Input
輸入一行包含兩個正整數\(K\)和\(N\)。
接下來\(N\)行,其中第\(i\)行包含\(3\)個整數\(S_i,P_i,R_i\)表示候選人i的招募費用,戰鬥值和推薦人編號。
對於\(100\%\)的數據滿足\(1≤K≤N≤2500,0<S_i,P_i≤10^4,0≤R_i<i.\)
Output
輸出一行一個實數,表示最佳比值。答案保留三位小數。
Sample Input
1 2
1000 1 0
1 1000 1
Sample Output
0.001
Solution
- \(0/1\)分數規劃與樹形背包的結合.
- 目標是最大化\(\sum a_i/\sum b_i\).
- 考慮二分答案\(x\),若該答案合法,則\(\sum a_i/\sum b_i\geq x\).
- 移項,有\(\sum a_i-x\cdot \sum b_i\geq 0\).
- 令每個物品的權值為\(a_i-x\cdot b_i\),則轉化為一般的最大化總權值的樹形背包.得出最大總權值後,若其非負,則說明\(x\)合法,否則不合法.
#include<bits/stdc++.h> #define inf 1e9 using namespace std; typedef long long LoveLive; const double eps=1e-5; inline int read() { int out=0,fh=1; char jp=getchar(); while ((jp>‘9‘||jp<‘0‘)&&jp!=‘-‘) jp=getchar(); if (jp==‘-‘) { fh=-1; jp=getchar(); } while (jp>=‘0‘&&jp<=‘9‘) { out=out*10+jp-‘0‘; jp=getchar(); } return out*fh; } const int MAXN=2510; int a[MAXN],b[MAXN],Fa[MAXN];//p,s,r int cnt=0,head[MAXN],to[MAXN<<1],nx[MAXN<<1]; double w[MAXN],f[MAXN][MAXN]; int sons[MAXN],siz[MAXN]; inline void add(int u,int v) { ++cnt; to[cnt]=v; nx[cnt]=head[u]; head[u]=cnt; } int n,k; void dfs(int u) { siz[u]=1; f[u][0]=0; if(sons[u]==0) { f[u][1]=w[u]; return; } for(int i=head[u];i;i=nx[i]) { int v=to[i]; dfs(v); int lim=min(k,siz[u]); for(int j=lim;j>=0;--j) { for(int p=0;p<=siz[v];++p) { if(j+p>k) break; f[u][j+p]=max(f[u][j+p],f[u][j]+f[v][p]); } } siz[u]+=siz[v]; } for(int i=k;i>=0;--i) { if(i>=1) f[u][i]=f[u][i-1]+w[u]; else f[u][i]=0; } } int check(double x) { for(int i=1;i<=n;++i) w[i]=1.0*a[i]-1.0*b[i]*x; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) f[i][j]=-inf; dfs(1); if(f[1][k]>-eps) return 1; return 0; } int main() { k=read(),n=read(); ++n,++k; for(int i=2;i<=n;++i) { b[i]=read(); a[i]=read(); Fa[i]=read(); ++Fa[i]; ++sons[Fa[i]]; add(Fa[i],i); } double L=0,R=1e4,ans=0; while(R-L>eps) { double mid=(L+R)/2; if(check(mid)) { ans=mid; L=mid; } else R=mid; } printf("%.3f\n",ans); return 0; }
bzoj 4753 最佳團體