zoukankan      html  css  js  c++  java
  • 【CF235D】Graph Game

    题目

    题目链接:https://codeforces.com/problemset/problem/235/D
    求基环树随机点分治总遍历次数期望。
    基环树随机点分治步骤:

    1. 遍历当前分治区域所有点一次。
    2. 在当前分治区域随机选择一个点 (x)
    3. (x) 删掉,产生的所有连通块递归处理。

    (nleq 3000)

    思路

    考虑枚举两个点 (x,y)(y) 能给 (x) 的贡献,其实就是当 (x) 作为分治中心的时候,(y)(x) 连通的期望。
    如果在树上,设 (x,y) 两点之间有 (d) 个点,很显然 (x)(y) 连通当前仅当 (x)(x)(y) 的链上第一个被删除的点,它的概率也就是 (frac{1}{d})
    这道题给出的是一棵基环树,如果两个点之间的路径只有 (1) 条,那么贡献就和树上一样。如果两点之间的路径有两条,容斥一下,设两条路径各自的点数分别为 (d1,d2),两条路径的并集的点数为 (d3),那么这一组点的贡献就是 (frac{1}{d1}+frac{1}{d2}-frac{1}{d3})
    时间复杂度 (O(n^2))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=3010;
    int n,m,tot,head[N],id[N],siz[N],rk[N],top[N],deg[N],dep[N],a[N];
    double ans;
    
    struct edge
    {
    	int next,to;
    }e[N*2];
    
    void add(int from,int to)
    {
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    }
    
    void topsort()
    {
    	queue<int> q;
    	for (int i=1;i<=n;i++)
    		if (deg[i]==1) q.push(i);
    	while (q.size())
    	{
    		int u=q.front(); q.pop();
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			deg[v]--;
    			if (deg[v]==1) q.push(v);
    		}
    	}
    }
    
    void dfs1(int x,int fa,int tp)
    {
    	top[x]=tp; dep[x]=dep[fa]+1;
    	id[x]=++tot; rk[tot]=x; siz[x]=1;
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (v!=fa && deg[v]<=1)
    		{
    			dfs1(v,x,tp);
    			for (int j=id[x];j<id[x]+siz[x];j++)
    				for (int k=id[v];k<id[v]+siz[v];k++)
    					ans+=2.0/(dep[rk[j]]+dep[rk[k]]-2*dep[x]+1);
    			siz[x]+=siz[v];
    		}
    	}
    }
    
    void dfs2(int x,int fa,int tp)
    {
    	a[x]=++m;
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (deg[v]>=2 && v!=fa && v!=tp)
    			return (void)(dfs2(v,x,tp));
    	}
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	for (int i=1,x,y;i<=n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		x++; y++;
    		add(x,y); add(y,x);
    		deg[x]++; deg[y]++;
    	}
    	topsort();
    	tot=0;
    	for (int i=1;i<=n;i++)
    		if (deg[i]>=2) dfs1(i,0,i);
    	for (int i=1;i<=n;i++)
    		if (deg[i]>=2) { dfs2(i,0,i); break; }
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    			if (top[i]!=top[j])
    			{
    				int d1=abs(a[top[i]]-a[top[j]])-1,d2=m-d1-2;
    				ans+=1.0/(dep[i]+dep[j]+d1)+1.0/(dep[i]+dep[j]+d2);
    				ans-=1.0/(dep[i]+dep[j]+m-2);
    			}
    	printf("%.12lf",ans+n);
    	return 0;
    }
    
  • 相关阅读:
    HTML/CSS的学习过程一览
    C++ MFC实现基于RFID读写器的上位机软件
    Java实现UDP之Echo客户端和服务端
    Java实现TCP之Echo客户端和服务端
    Java实现Socket之WhoisClient
    Java实现Socket之TimeClient
    openWRT自学---针对backfire版本的主要目录和文件的作用的分析整理
    openWRT自学计划安排
    openWRT自学---对官方的开发指导文档的解读和理解 记录2:如何控制内核模块的编译
    openWRT自学---对官方的开发指导文档的解读和理解 记录1:编译一个package
  • 原文地址:https://www.cnblogs.com/stoorz/p/15173257.html
Copyright © 2011-2022 走看看