zoukankan      html  css  js  c++  java
  • POJ 2057 The Lost House

    vjudge

    智商掉线*2...

    可以看成求一种遍历叶子的顺序,使得以每个叶子为终点的路径的长度之和最小.考虑设(f_x)表示(x)子树内,以(x)为起点到所有叶子的路径长度之和的最小值,(g_x)表示从(x)父亲走进子树(x)然后遍历完一遍后出来的步数(也就是没走进终点所在子树而要浪费的步数),(s_x)表示(x)子树内叶子节点个数

    先考虑(g_x),如果没有worm那么就是子树大小(*2).否则因为worm会告诉snail终点不在这个子树内,那么要遍历的联通块大小就是所有worm节点断掉儿子的边以后的联通块大小,(g_x)就是这个联通块大小(*2)

    然后是(f_x),因为终点可能在所有儿子子树内,所以后遍历的子树的步数要加上前面遍历子树浪费的步数(g_y),转移要枚举遍历儿子的顺序,然后大概长这样$$f_x=(sum_{yin son_of_x}f_y )+(min_{{p1,p2,p3...p_{cnt}}=son_of_x}sum_{i=1}{cnt}s_{p_i}*(1+sum_{j=1}{i-1}g_{p_j}))$$

    考虑后半部分,这个式子有点国王游戏,考虑交换两个相邻儿子的枚举顺序来优化答案,首先这不会对其他的儿子贡献产生影响,然后如果(i)号放(i+1)号儿子前面更优,相当于这种情况的和比(i)放后面的和要小,进一步化简可以得到要满足(s_ig_{i+1}>s_{i+1}g_i)这个条件,所以可以按照这个为关键字排序,然后一遍扫过去得到(f_x).最后输出(frac{f_{root}}{s_{root}})

    #include<bits/stdc++.h>
    //poj 不能用bits头,请选c++编译器
    #define LL long long
    #define uLL unsigned long long
    #define db double
    
    using namespace std;
    const int N=1000+10;
    int rd()
    {
    	int x=0,w=1;char ch=0;
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*w;
    }
    int to[N<<1],nt[N<<1],hd[N],tot=1;
    void add(int x,int y)
    {
    	++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
    	++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
    }
    char cc[N];
    bool v[N],bb[N];
    int n,rt,sz[N],ss[N],st[N],tp;
    bool cmp(int aa,int bb){return 1ll*ss[aa]*sz[bb]>1ll*ss[bb]*sz[aa];}
    LL f[N];
    void dp(int x,int ffa)
    {
    	sz[x]=1,ss[x]=f[x]=0;
    	if(ffa&&!nt[hd[x]]){ss[x]=1;return;}
    	for(int i=hd[x];i;i=nt[i])
    	{
    		int y=to[i];
    		if(y==ffa) continue;
    		dp(y,x),ss[x]+=ss[y];
    		if(!v[x]) sz[x]+=sz[y];
    	}
    	tp=0;
    	for(int i=hd[x];i;i=nt[i])
    	{
    		int y=to[i];
    		if(y==ffa) continue;
    		st[++tp]=y,f[x]+=f[y]+ss[y];
    	}
    	sort(st+1,st+tp+1,cmp);
    	LL dt=0;
    	for(int i=1;i<=tp;++i)
    	{
    		int y=st[i];
    		f[x]+=ss[y]*dt;
    		dt+=sz[y]*2;
    	}
    }
    
    int main()
    {
    	int T=rd();
    	while(T--)
    	{
    		n=rd();
    		for(int i=1;i<=n;++i) hd[i]=0;
    		tot=1;
    		for(int i=1;i<=n;++i)
    		{
    			int y=rd();
    			if(y>0) add(i,y);
    			else rt=i;
    			scanf("%s",cc);
    			v[i]=cc[0]=='Y';
    		}
    		dp(rt,0);
    		printf("%.4lf
    ",f[rt]/(db)ss[rt]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [HAOI2008]糖果传递
    LGTB 与大数
    LGTB 与序列
    poj1160 Post Office
    组队
    [JLOI2015]装备购买
    三元组
    乘法表
    [BZOJ3730]震波
    [Luogu3345][ZJOI2015]幻想乡战略游戏
  • 原文地址:https://www.cnblogs.com/smyjr/p/11435485.html
Copyright © 2011-2022 走看看