题目描述
某个公司有n个人, 上下级关系构成了一个有根树。其中有个人是叛徒(这个人不知道是谁)。对于一个人, 如果他 下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变 成叛徒。你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k。
题目分析
其实这就是一道(思博)DP题,首先,因为最开始这有一个人是叛徒,所以叛徒必然是从叶节点向跟延伸的。我们不妨设
dp[i]
表示以
i
为根的子树中全变叛徒的最小的x, 于是有
dp[i]=max( min(dp[j],sz[j]/(sz[i]−1)+EPS) ) | j为i的儿子
然后对于每一个大于
k
的子树累加ans=max(ans,dp[i])|sz[i]≥k就行了。
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 500000
#define MAXM 500000
#define INF 0x3f3f3f3f
typedef long long int LL;
template<
class T>
void Read(T &x){
x=
0;
char c=getchar();
bool flag=
0;
while(c<
'0'||
'9'<c){
if(c==
'-')flag=
1;c=getchar();}
while(
'0'<=c&&c<=
'9'){x=x*
10+c-
'0';c=getchar();}
if(flag)x=-x;
}
const double EPS =
1e-9;
int Sign(
const double x){
if(x>EPS)
return 1;
else if(x<-EPS)
return -
1;
else return 0;
}
double fmax(
const double x,
const double y){
if(Sign(x-y)>=
0)
return x;
else return y;
}
double fmin(
const double x,
const double y){
if(Sign(x-y)<=
0)
return x;
else return y;
}
struct node{
int v;
node *nxt;
}*adj[MAXN+
10],Edges[MAXM+
100],*New=Edges;
void addedge(
int u,
int v){
node *p=++New;
p->v=v;
p->nxt=adj[u];
adj[u]=p;
}
int n,k;
int sz[MAXN+
10];
double dp[MAXN+
10];
void dfs(
int x){
sz[x]=
1;
for(node *p=adj[x];p!=NULL;p=p->nxt){
dfs(p->v);
sz[x]+=sz[p->v];
}
if(sz[x]==
1)dp[x]=
1.0;
else{
for(node *p=adj[x];p!=NULL;p=p->nxt)
dp[x]=fmax(dp[x],fmin(dp[p->v],(
double)sz[p->v]/(sz[x]-
1)+EPS));
}
}
int main(){
Read(n),Read(k);
int x;
for(
int i=
2;i<=n;++i)
Read(x),addedge(x,i);
dfs(
1);
double ans=
0;
for(
int i=
1;i<=n;++i)
if(sz[i]>k)ans=max(ans,dp[i]);
printf(
"%0.8lf\n",ans);
}
转载请注明原文地址: https://ju.6miu.com/read-6959.html