hdu 5946 Fxx and tree

Problem Description
Young theoretical computer scientist Fxx has a tree.

You are given a rooted tree with n vertices,numbered from 1 to n(vertex 1 is the root).Each vertex of the tree has a value  Ai  and a color,which is either black or white.

Now consider a reverse operation: Choose a vertex  X  randomly.When X is chosen,its color changes.Meanwhile,the color of a vertex  K  changes as well if and only if  X  is an ancestor of  K  and the distance between them is no more than  AX .

Fxx need to find out the expected number of operations to turn the whole tree black.Can you help him?
 

Input
In the first line, there is an integer  T(T100)  indicating the number of test cases.

For each test case,the first line contains one integers n(1\leq n\leq 50), indicating the number of vertice.

In the next n-1 lines, Each line contains two integers  u  and  v  meaning that vertice  u  is the father of vertice  v .

In the next line contains  n  integers  A1,A2,,An(0Axn) .

In the next line contains  n  integers  C1,C2,,Cn , indicating the color of each vertice( Cx=0  means the color of vertice  x  is white,  Cx=1  means the color of vertice  x  is black)
 

Output
For each test case, output the answer.

Each answer is rounded to three decimal places.

For example,if the answer is "<b>3.7998</b>", you should output “3.800”.
 

Sample Input
  
  
1 2 1 2 0 0 1 0
 

Sample Output
  
  
3.000
 

Source

BestCoder Round #89



给你一棵树,点有黑白两色。每次随机选一个点,把他和他子树中距离<=ai的点颜色翻转

问期望把整棵树变黑的操作次数


这题的出题人绝对不适合出题

首先a和c在测试数据中是反的

然后这题这么高的精度不给个SPJ,导致写法不同基本过不去

我随机他的范围有的数据要输出多达18位有效数字


讲下做法吧

这题很明显是高斯消元的题目

首先我们发现,对于一个点,所有能影响到他的父亲状态如果确定,那么他的操作状态也就确定了

f[i]表示有i个点状态和最终状态【黑】不同,到期望状态的操作数

那么有转移式f[i]=f[i+1]*(n-i)/n+f[i-1]*i/n+1;

然后我们可以列出方程组,解出来即可

有x个点状态不同那么答案就是f[x]

贴个过不去的代码吧。对拍的时候精度被卡掉了

#include<cstdio>
#include<string>
#include<iomanip>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct line
{
	int s,t;
	int next;
}a[101];
int head[51];
int edge;
inline void add(int s,int t)
{
	a[edge].next=head[s];
	head[s]=edge;
	a[edge].s=s;
	a[edge].t=t;
}
long double eps=1e-12;
bool l[511];
long double ans[511];
long double ax[511][511]; 
int n;
inline int solve()
{
	int res=0,r=1;
	int i,j,k;
	for(i=1;i<=n;i++)
		l[i]=false;
	for(i=1;i<=n;i++)
	{
		for(j=r;j<=n;j++)
		{
			if(fabs(ax[j][i])>eps)
			{
				for(k=i;k<=n+1;k++)
					swap(ax[j][k],ax[r][k]);
				break;
			}
		}
		if(fabs(ax[r][i])<eps)
		{
			res++;
			continue;
		}
		for(j=1;j<=n;j++)
		{
			if(j!=r&&fabs(ax[j][i])>eps)
			{
				long double tmp=ax[j][i]/ax[r][i];
				for(k=i;k<=n+1;k++)
					ax[j][k]-=tmp*ax[r][k];
			}
		}
	/*	for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n+1;j++)
				printf("%.3f ",ax[i][j]);
			printf("\n");
		}
		printf("\n");*/
		l[i]=true;
		r++;
	}
	for(i=1;i<=n;i++)
	{
		if(l[i])
		{
			for(j=1;j<=n;j++)
			{
				if(fabs(ax[j][i])>eps)
					ans[i]=ax[j][n+1]/ax[j][i];
			}
		}
	}
	return res;
}
int x1[51],x2[51],fa[51];
int edg[51];
bool fx[51],v[51];
inline void findx(int d,int dep,int lim)
{
	if(dep>lim)
		return ;
	if(dep!=0)
		v[d]=(!v[d]);
	int i;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		findx(t,dep+1,lim);
	}
}
inline void dfs(int d)
{
	int i,s=1,t=fa[d],sum=0;
	if(v[d])
		fx[d]=(x2[d]==1);
	else
		fx[d]=(x2[d]!=1);
	if(fx[d])
		findx(d,0,x1[d]);
	for(i=head[d];i!=0;i=a[i].next)
	{
		t=a[i].t;
		dfs(t);
	}
}
int main()
{
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	int T;
	scanf("%d",&T);
	while(T>0)
	{
		T--;
		scanf("%d",&n);
		memset(head,0,sizeof(head));
		memset(edg,0,sizeof(edg));
		edge=0;
		int i,s,t;
		for(i=1;i<=n-1;i++)
		{
			scanf("%d%d",&s,&t);
			edge++;
			add(s,t);
			edg[t]++;
			fa[t]=s;
		}
		for(i=1;i<=n;i++)
			scanf("%d",&x2[i]);
		for(i=1;i<=n;i++)
			scanf("%d",&x1[i]);
		memset(ax,0,sizeof(ax)); 
		long double nn=(long double)n;
		/*ax[1][1]=nn;
		ax[1][2]=-(long double)(n-1);
		ax[1][n+1]=nn;*/
		ax[1][1]=1;
		ax[1][2]=-(long double)(n-1)/nn;
		ax[1][n+1]=1;
		for(i=2;i<=n;i++)
		{
			/*ax[i][i-1]=-(long double)i;
			ax[i][i]=nn;
			ax[i][i+1]=-(long double)(nn-i);
			ax[i][n+1]=nn;*/
			ax[i][i-1]=-(long double)i/nn;
			ax[i][i]=1;
			ax[i][i+1]=-(long double)(nn-i)/nn;
			ax[i][n+1]=1;
		}
	/*	for(i=1;i<=n;i++)
		{
			for(int j=1;j<=n+1;j++)
				printf("%.3f ",ax[i][j]);
			printf("\n");
		}
		printf("\n");*/
		memset(v,false,sizeof(v));
		solve();
		int rt=0;
		for(i=1;i<=n;i++)
			if(edg[i]==0)
				rt=i;
		fa[rt]=0;
		memset(fx,false,sizeof(fx));
		dfs(rt);
		int sum=0;
		for(i=1;i<=n;i++)
			if(fx[i])
				sum++;
		printf("%.3f\n",double(ans[sum]));
	//	cout<<fixed<<setprecision(3)<<ans[sum]<<endl;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值