您的位置:首页 > 其它

【BZOJ 4726】【POI 2017】[动态规划]Sabota?

2017-03-08 22:10 176 查看

题目描述

某个公司有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就行了。

代码

/**************************************************************
Problem: 4726
User: bzjudge2
Language: C++
Result: Accepted
Time:6508 ms
Memory:24652 kb
****************************************************************/

#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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poi dp