2878: [Noi2012]迷失游乐园
Time Limit: 10 Sec Memory Limit: 512 MBSec Special Judge
Submit: 319 Solved: 223
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
分析本题发现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)