NOI2012 迷失游乐园

http://www.lydsy.com/JudgeOnline/problem.php?id=2878

比较容易的概率题。

Case1~5:

这是一棵树。

我们求出每个点i度数du[i],只走子树的期望距离g[i]和不走子树的期望距离f[i],这比较好求。

然后累加即可。

Case6~10:

图中有一个环,然后环上的点都是一棵树的根。

对于每棵树,我们同样求出每个点i度数du[i],只走子树的期望距离g[i]。

那么怎么求不走子树的期望距离f[i]呢?

我们先求环上的点的f[i]吧。

我们枚举环上的点i,再枚举环上的另一个点j,求出i能到到j的距离概率和距离(有2个方向,都一样),然后f[i]+=概率*(距离+g[j])。

现在每棵树的根节点的不走子树的期望距离f[i]已经算出来了,然后树中的点f[i]也就很容易了。

然后累加即可。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj

using namespace std;

typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP;

#define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b)  for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define SF scanf
#define PF printf
#define two(k) (1<<(k))

template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}

const DB EPS=1e-9;
inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
const DB Pi=acos(-1.0);

inline void clear(vector<int> *A,int a,int b){int i,j;A->clear();re(i,0,a)re(j,0,b)A[i].push_back(0);}

inline int gint()
  {
        int res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }
inline LL gll()
  {
      LL res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }

const int maxN=100000;

int N,M;
int now,first[maxN+100];
struct Tedge{int v,next,dis;}edge[2*maxN+100];

DB ans;

int cnt,root[maxN+100];
int id[maxN+100];
DB lon[maxN+100],val[maxN+100],h[maxN+100];

inline void addedge(int u,int v,int dis)
  {
      now++;
      edge[now].v=v;
      edge[now].dis=dis;
      edge[now].next=first[u];
      first[u]=now;
  }

int du[maxN+100],fa[maxN+100];
DB g[maxN+100],f[maxN+100];

int head,tail,que[maxN+100];

inline void BFS(int S)
  {
      int i,j;
      que[head=tail=1]=S;
      fa[S]=0;
      du[S]=0;
      while(head<=tail)
        {
            int u=que[head++],v;
            for(i=first[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)if(v!=fa[u] && id[v]==0)
                  {
                      fa[que[++tail]=v]=u;
                        du[u]++;
                        du[v]=1;
                    }
        }
      red(j,tail,1)
        {
            int u=que[j],v,dis;
            g[u]=0.0;
            for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-1;i=edge[i].next,v=edge[i].v,dis=edge[i].dis)if(v!=fa[u] && id[v]==0)g[u]+=DB(dis)+g[v];
            int t=(u==S)?du[u]:du[u]-1;
                if(t!=0)g[u]/=DB(t);
        }
  }

inline void BFS2(int S)
  {
      int i,j;
      que[head=tail=1]=S;
      fa[S]=0;
      while(head<=tail)
        {
            int u=que[head++],v;
            for(i=first[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)if(v!=fa[u] && id[v]==0) fa[que[++tail]=v]=u;
        }
      re(j,1,tail)
        {
            int u=que[j],v,dis;
            DB sum=0.0;
            for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-1;i=edge[i].next,v=edge[i].v,dis=edge[i].dis)if(v!=fa[u] && id[v]==0)sum+=DB(dis)+g[v];
            if(M==N && id[u]!=0) sum+=f[u]+f[u]; else sum+=f[u];
            int t=du[u]-1;
            for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-1;i=edge[i].next,v=edge[i].v,dis=edge[i].dis)if(v!=fa[u] && id[v]==0)
              {
                   f[v]=sum-DB(dis)-g[v];
                  if(t!=0)f[v]/=DB(t);
                  f[v]+=DB(dis);
              }
        }
  }

int vis[maxN+100];
int top,sta[maxN+100],last[maxN+100];
inline void DFS()
  {
      mmst(vis,0);
      mmst(fa,0);
      vis[sta[top=1]=1]=1;
      last[1]=first[1];
      while(top>=1)
        {
            int u=sta[top],i=last[top],v;
            for(v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)
              {
                if(!vis[v])
                  {
                      vis[sta[++top]=v]=1;
                      last[top]=first[v];
                      fa[v]=u;
                      last[top-1]=edge[i].next;
                      break;
                    }
                if(v!=fa[u] && vis[v])
                  {
                      while(sta[top]!=v)root[++cnt]=sta[top--];
                      root[++cnt]=v;
                      return;
                  }
              }
                if(i==-1)vis[sta[top--]]=0;
        }
  }

int main()
  {
      freopen("park.in","r",stdin);
      freopen("park.out","w",stdout);
      int i,j;
      N=gint();M=gint();
      mmst(first,-1);now=-1;
      re(i,1,M)
        {
            int x=gint(),y=gint(),dis=gint();
            addedge(x,y,dis);
            addedge(y,x,dis);
        }
      if(M==N-1)
        {
            BFS(1);
            mmst(fa,0);
                f[1]=0.0;BFS2(1);
            ans=0.0;
            re(i,1,N)
              {
                  int t=(i==1)?du[i]:du[i]-1;
                  ans+=g[i]*(DB(t)/DB(du[i]))+f[i]*(1.0-DB(t)/DB(du[i]));
              }
          ans/=DB(N);
            PF("%0.5lf\n",ans);
            return 0;
        }
      else
        {
            DFS();
            re(i,1,cnt)id[root[i]]=i;
            re(i,1,cnt)BFS(root[i]);
            #define next(i) (i%cnt+1)
            #define qian(i) (((i-2)%cnt+cnt)%cnt+1)
            re(j,1,cnt)
              {
                  int i,v,dis;
                  for(i=first[root[j]],v=edge[i].v,dis=edge[i].dis;i!=-1;i=edge[i].next,v=edge[i].v,dis=edge[i].dis)if(v==root[next(j)]){lon[j]=DB(dis);break;}
              }
            re(i,1,cnt)
              {
                  h[i]=0.0;
                  int p=i;
                  DB gailv=1e10,t=0.0;
                  while(1)
                    {
                        if(p==i) gailv/=2.0; else gailv/=DB(du[root[p]]+1);
                        t+=lon[p];
                        p=next(p);
                                if(next(p)!=i)
                                  h[i]+=gailv*(DB(du[root[p]])/DB(du[root[p]]+1))*(t+g[root[p]]);
                                else
                                  {
                                      h[i]+=gailv*(t+g[root[p]]);
                                      break;
                                  }
                    }
                  p=i;
                        gailv=1e10;
                        t=0.0;
                  while(1)
                    {
                        if(p==i) gailv/=2.0; else gailv/=DB(du[root[p]]+1);
                        t+=lon[qian(p)];
                        p=qian(p);
                        if(qian(p)!=i)
                            h[i]+=gailv*(DB(du[root[p]])/DB(du[root[p]]+1))*(t+g[root[p]]);
                        else
                          {
                              h[i]+=gailv*(t+g[root[p]]);
                              break;
                          }
                    }
                  h[i]/=1e10;
              }
            mmst(fa,0);
            re(i,1,cnt)du[root[i]]+=2,f[root[i]]=h[i],BFS2(root[i]);
            ans=0.0;
            re(i,1,N)
              {
                  int t=(id[i]!=0)?du[i]-2:du[i]-1;
                  ans+=g[i]*(DB(t)/DB(du[i]))+f[i]*(1.0-DB(t)/DB(du[i]));
              }
          ans/=DB(N);
          PF("%0.5lf\n",ans);
            return 0;
          }
      return 0;
  }

时间: 2024-10-14 18:29:57

NOI2012 迷失游乐园的相关文章

BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )

一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. --------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm&

BZOJ 2878([Noi2012]迷失游乐园-树形DP+环加外向树+期望DP+vector的erase)

2878: [Noi2012]迷失游乐园 Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge Submit: 319  Solved: 223 [Submit][Status] Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m只可能等于n或者n-1).小Z现在所在的大门也正好是

【BZOJ 2878】 [Noi2012]迷失游乐园

2878: [Noi2012]迷失游乐园 Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge Submit: 415  Solved: 283 [Submit][Status] Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m只可能等于n或者n-1).小Z现在所在的大门也正好是

bzoj2878 [Noi2012]迷失游乐园 [树形dp]

Description 放假了,小Z认为呆在家里特别无聊.于是决定一个人去游乐园玩. 进入游乐园后.小Z看了看游乐园的地图,发现能够将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m仅仅可能等于n或者n-1).小Z如今所在的大门也正好是一个景点. 小Z不知道什么好玩,于是他决定,从当前位置出发,每次随机去一个和当前景点有道路相连的景点,而且同一个景点不去两次(包括起始景点).贪玩的小Z会一直游玩.直到当前景点的相邻景点都已经訪问过为止.小Z全部经过的景点按顺序构成一条非反

BZOJ 2878: [Noi2012]迷失游乐园

Writing now. 1 /************************************************************** 2 Problem: 2878 3 User: zrts 4 Language: C++ 5 Result: Accepted 6 Time:588 ms 7 Memory:10748 kb 8 ****************************************************************/ 9 10 #i

BZOJ 2878 [Noi2012]迷失游乐园 树形期望DP+基环树

题意:链接 方法:树形期望DP+基环树 解析: 首先先看前50%的数据 是一棵树 那么我们可以搞树形DP 然后设几个正常的数组 sum[i]代表i走i的子节点的期望的和. down[i]代表从底下走到i的期望. size[i]代表i的儿子个数 up[i]代表从i往上走的期望 然后就可以推式子了 显而易见地可以推出来up的式子 然后有一些奇怪的关于根节点的特判,注意一下就OK了. 然后后50% 我们发现它是一个基环树? 那么首先可以乱搞出来环上的点,然后记录一下这个环上的点的连接方式,求一下相邻两

[bzoj2878][Noi2012]迷失游乐园(基环树dp)

bzoj luogu 题意:一颗数或是基环树,随机从某个点开始一直走,不走已经到过的点,求无路可走时的路径长期望. 对于一棵树: 用两个$dp$数组分别记录从这个点起向上向下走的期望 向下走的$dp$不用多说 向上走的$dp$: 对于从$u$计算$v$的dp $dp[v]$应当是从u向周围引出所有路径减去走向t的路径的期望后再除以$deg_{u}-1$ 对于基环树: 环上的点很少. 此时环上的点的向上$dp$指从u出发向环上两头走的期望. 如何计算:对于环上每一个点都向环的两头各dp一次取平均值

【BZOJ】【2878】【NOI2012】迷失游乐园

树形+基环树DP/数学期望 然而我并不会做…… 题解戳这里:http://blog.csdn.net/u011265346/article/details/46328543 好吧先考虑一个简单点的,当m=n-1时,整个是一个树形的结构,无根树我们一般还是转成有根树来处理……然后既然是无法回头的,那么我们可以定一下方向:向下或者向上(废话) 定义一下: son[x]为x的儿子的数量 down[x]表示从x这个点出发,向叶子们走的期望长度. 怎么算呢?其实就是所有可能的情况(所有的儿子)加起来,再求

YCB 的暑期计划

前言 YCB现在很弱(TAT) 暑假有一个月,赶快狂补一下. 大概的计划如下: 首先前期会以数据结构为主,毕竟代码能力太弱,涉及内容:线段树分治.二进制分组.KD-Tree. 等数据结构做到没有智商的时候加入一波数论,内容为 杜教筛.min_25筛. 然后中途小清新一下,做一些 组合博弈与构造题. 接着继续练代码能力,顺便学一些神奇的暴力:启发式合并.dsu on tree . 然后图论也忘的差不多了,就回过头去学点新东西,大概会有spfa判负环.0/1分数规划.差分约束. 估计这个时候也没有什