SPOJ AMR12K The Loyalty of the Orcs 解题报告

来源:互联网 发布:银行存取款数据库设计 编辑:程序博客网 时间:2024/05/16 04:15

题目

Summer Training 06 - Amritapuri 2012 总结

题意:

给世界上最纯正的英语跪了,我真的读了好多好多遍……简单来说就是有一棵树,有一些节点已经死了。随机一个1~N的序列,按序列检查这个节点是否已死并计数加1.有一种优化的方法,就是如果在检查这个节点之前已经发现它有祖先死了,那就不+1了。求优化的方法省下来的检查次数的期望。

题解:

显然不优化的话所有点都检查,那么计数为N。如果优化的话,要使得某个节点检查的话,它所有死了的祖先都得放在它后面检查。设某节点有K个祖先死了,那放在它后面的排列是K!,剩下的(n-k-1)个点就随便放,方案数是n!/(k+1)!,总的方案数是n!,所以这个检点检查的概率是1/(k+1)。全部节点的概率加起来用n一减就是期望。

//Time:370ms//Memory:10240KB//Length:1060B#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <set>#define MAXN 200010using namespace std;int he[MAXN],to[MAXN],nex[MAXN],top;bool vi[MAXN];double ans;void add(int u,int v){    to[top]=v;    nex[top]=he[u];    he[u]=top++;}void dfs(int h,int cnt,int fa){    ans+=1.0/cnt;    for(int i=he[h];i!=-1;i=nex[i])        if(fa!=to[i])            dfs(to[i],cnt+vi[h],h);}int main(){    //freopen("/home/moor/Code/input","r",stdin);    int ncase,n,m;    scanf("%d",&ncase);    while(ncase--)    {        ans=0;        scanf("%d",&n);        memset(he,-1,sizeof(he));        memset(vi,0,sizeof(vi));        top=0;        for(int i=1;i<n;++i)        {            int u,v;            scanf("%d%d",&u,&v);            add(u,v);            add(v,u);        }        scanf("%d",&m);        for(int i=0;i<m;++i)        {            int tmp;            scanf("%d",&tmp);            vi[tmp]=1;        }        dfs(1,1,-1);        printf("%.8f\n",n-ans);    }    return 0;}


原创粉丝点击