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现在所在的大门也正好是一个景点。小Z不知道什么好玩,于是他决定,从当前位置出发,每次随机去一个和当前景点有道路相连的景点,并且同一个景点不去两次(包括起始景点)。贪玩的小Z会一直游玩,直到当前景点的相邻景点都已经访问过为止。小Z所有经过的景点按顺序构成一条非重复路径,他想知道这条路径的期望长度是多少?小Z把游乐园的抽象地图画下来带回了家,可是忘了标哪个点是大门,他只好假设每个景点都可能是大门(即每个景点作为起始点的概率是一样的)。同时,他每次在选择下一个景点时会等概率地随机选择一个还没去过的相邻景点。

Input

第一行是两个整数n和m,分别表示景点数和道路数。 接下来行,每行三个整数Xi, Yi, Wi,分别表示第i条路径的两个景点为Xi, Yi,路径长Wi。所有景点的编号从1至n,两个景点之间至多只有一条道路。

Output

共一行,包含一个实数,即路径的期望长度。

Sample Input

4 3

1 2 3

2 3 1

3 4 4

Sample Output

6.00000000

【样例解释】样例数据中共有6条不同的路径: 路径 长度 概率

1-->4 8 1/4

2-->1 3 1/8

2-->4 5 1/8

3-->1 4 1/8

3-->4 4 1/8

4-->1 8 1/4

因此期望长度 = 8/4 + 3/8 + 5/8 + 4/8 + 4/8 + 8/4 = 6.00

【评分方法】本题没有部分分,你程序的输出只有和标准答案的差距不超过0.01时,才能获得该测试点的满分,否则不得分。

【数据规模和约定】对于100%的数据,1 <= Wi <= 100。 测试点编号 n m 备注

1 n=10 m = n-1 保证图是链状

2 n=100 只有节点1的度数大于2

3 n=1000 /

4 n=100000 /

5 n=100000 /

6 n=10 m = n /

7 n=100 环中节点个数<=5

8 n=1000 环中节点个数<=10

9 n=100000 环中节点个数<=15

10 n=100000 环中节点个数<=20

HINT

Source

鸣谢Ljcc提供SPJ

分析本题发现m=n-1或m=n,且图连通.

故图为树或环加外向树

树:

对节点x,考虑向下走和向上走两种情况,期望分别为down[x]和up[x]

环加外向树:

对环上每棵树的down[],同上

考虑环上节点的up[],k^2大暴力硬算

非环节点的up[],可由环上节点up[]求出,方法仍同上

PS:考虑“无路可走”时,期望=0.0

在本题中有vector的erase(q.begin(),q.begin()+k)函数用法(删除[0,k)区间)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<vector>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (100000+10)
#define MAXM (300000+10)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
typedef long double ld;

int n,m,edge[MAXM],pre[MAXN]={0},next[MAXM]={0},weight[MAXM],size=0;
void addedge(int u,int v,int w){edge[++size]=v;weight[size]=w;next[size]=pre[u],pre[u]=size;}
void addedge2(int u,int v,int w){addedge(u,v,w),addedge(v,u,w);}
long double up[MAXN]={0.0},down[MAXN]={0.0};
int fa[MAXN]={0},son[MAXN]={0};
void dfs_down(int x)
{
	Forp(x)
	{
		int v=edge[p];
		if (v^fa[x])
		{
			fa[v]=x;son[x]++;
			dfs_down(v);
			down[x]+=(ld)(weight[p]+down[v]);
		}
	}
	if (son[x]) down[x]/=(ld)son[x];
}
void dfs_up(int x)
{
	ld sum=0.0;
	Forp(x)
	{
		int v=edge[p];
		if (v^fa[x])
		{
			sum+=(ld)weight[p]+down[v];
		}
	}
	if (fa[x]) sum+=up[x];
	Forp(x)
	{
		int v=edge[p];
		if (v^fa[x])
		{
			up[v]=sum-(ld)weight[p]-down[v];
			if ((son[x]-(!fa[x]))) up[v]/=(son[x]-(!fa[x]));
			up[v]+=(ld)weight[p];
			dfs_up(v);
		}
	}
}
bool b[MAXN]={0},b2=0;
vector<int> q,q2;
void print()
{
/*	cout<<q.size()<<endl;
	Rep(i,q.size()) cout<<q[i]<<' ';cout<<endl;
	cout<<q2.size()<<endl;
	Rep(i,q2.size()) cout<<q2[i]<<' ';cout<<endl;
*/
}
void find_circle(int x)
{
	b[x]=1;q.push_back(x);
	Forp(x)
	{
		int v=edge[p];
		if (!b[v])
		{
			q2.push_back(weight[p]);find_circle(v);
			if (b2) return;
		}
		else if (q[q.size()-2]^v)
		{
			int k=0;
			while(q[k]^v) k++;
			print();
			q.erase(q.begin(),q.begin()+k);
			q2.erase(q2.begin(),q2.begin()+k);
			q2.push_back(weight[p]);
			b2=1;return;
		}
	}
	q.pop_back();q2.pop_back();
}
void circle_down()
{
	int size=q.size();
	Rep(i,size)
	{
		int x=q[i];
		ld sum=0.0;
		Forp(x)
		{
			int v=edge[p];
			if ((v^q[(i-1+size)%size])&&v^(q[(i+1)%size]))
			{
				fa[v]=x;son[x]++;
				dfs_down(v);
				down[x]+=(ld)(weight[p]+down[v]);
			}
		}
		if (son[x]) down[x]/=(ld)son[x];
	}
}
void circle_up()
{
	int size=q.size();
	Rep(i,size)
	{
		int x=q[i];
		//处理环
		ld p=1.0/(ld)(2),w_past=0.0;
		For(j,size-1)
		{
			w_past+=q2[(i+j-1)%size];
			int v=q[(i+j)%size];
			if (j!=size-1) up[x]+=p*son[v]/(ld)(son[v]+1)*(w_past+down[v]);
			else up[x]+=p*(w_past+down[v]);
			p/=(ld)son[v]+1;
		}
		p=1.0/(ld)(2),w_past=0.0;
		For(j,size-1)
		{
			w_past+=q2[(i-j+size)%size];
			int v=q[(i-j+size)%size];
			if (j!=size-1) up[x]+=p*son[v]/(ld)(son[v]+1)*(w_past+down[v]);
			else up[x]+=p*(w_past+down[v]);
			p/=(ld)son[v]+1;
		}
		//处理子节点
		ld sum=0.0;
		Forp(x)
		{
			int v=edge[p];
			if ((v^q[(i-1+size)%size])&&v^(q[(i+1)%size]))
			{
				sum+=(ld)weight[p]+down[v];
			}
		}
		Forp(x)
		{
			int v=edge[p];
			if ((v^q[(i-1+size)%size])&&v^(q[(i+1)%size]))
			{
				up[v]=sum-(ld)weight[p]-down[v];
				up[v]/=(ld)(son[x]+1);
				up[v]+=(2.0/(ld)(son[x]+1))*up[x];
				up[v]+=(ld)weight[p];
				dfs_up(v);
			}
		}		

	}
}
int main()
{
//	freopen("bzoj2878.in","r",stdin);
//	freopen("bzoj2878.out","w",stdout);
	scanf("%d%d",&n,&m);
	For(i,m)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		addedge2(u,v,w);
	}
//	For(i,n)
//		Forp(i) cout<<i<<' '<<edge[p]<<' '<<weight[p]<<endl;
	cout.setf(ios::fixed);
	cout.precision(5);

	if (m==n-1)
	{
		dfs_down(1);dfs_up(1);
	//	For(i,n) cout<<i<<":"<<down[i]<<' '<<up[i]<<endl;
		ld ans=0.0;
		For(i,n) if (fa[i]) ans+=((ld)son[i]*down[i]+up[i])/(son[i]+1);
		else ans+=down[i];
		ans/=(ld)n;
		cout<<ans<<endl;
	}
	else
	{
		find_circle(1);
		print();
		circle_down();
		circle_up();
//		For(i,n) cout<<i<<':'<<down[i]<<' '<<up[i]<<endl;

		MEM(b);
		Rep(i,q.size()) b[q[i]]=1;
		ld ans=0.0;
		For(i,n)
			if (b[i]) ans+=2.0/(ld)(son[i]+2)*up[i]+(ld)(son[i])/(ld)(son[i]+2)*down[i];
			else ans+=1.0/(ld)(son[i]+1)*up[i]+(ld)(son[i])/(ld)(son[i]+1)*down[i];
		ans/=(ld)n;
		cout<<ans<<endl;
	}

	return 0;
}

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

时间: 2024-11-19 15:30:18

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

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

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

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

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

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

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

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

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如今所在的大门也正好

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

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

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]吧. 我们枚举

bzoj 2879: [Noi2012]美食节(费用流+动态加边)

2879: [Noi2012]美食节 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 1453 Solved: 778 [Submit][Status][Discuss] Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的... http://bbs.chinaacc.com/forum-2-3/topic-5785721.html ht