2878: [Noi2012]迷失游乐园
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1155 Solved: 625
[ Submit][ Status][ Discuss]
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
1 2 3
2 3 1
3 4 4
Sample Output
6.00000
【样例解释】样例数据中共有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
【样例解释】样例数据中共有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
fa数组:对于环上的点有2个父亲
f数组:向下递推
g数组:向上递推
#include"cmath"
#include"cstdio"
#include"iostream"
#include"cstring"
#include"algorithm"
#include"vector"
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
int n,m;
double fa[maxn],sz[maxn];
double f[maxn],g[maxn],ans;
bool vis[maxn],flag;
int mo[maxn],be;
int que[51],cnt,side[51];
struct edge{
int v,nxt,c;
edge(){}
edge(int v, int nxt, int c) : v(v), nxt(nxt), c(c){}
}e[maxn];
int tail,head[maxn];
int getmo(int x)
{
if(x == mo[x]) return x;
return mo[x] = getmo(mo[x]);
}
void init()
{
tail = -1;
memset(head,-1,sizeof(head));
}
void add(int u,int v, int c)
{
e[++tail] = edge(v,head[u],c);
head[u] = tail;
}
void dfsdown(int u,int last)
{
for(int i = head[u]; ~i; i = e[i].nxt){
int v = e[i].v;
if(vis[v] || v == last) continue;
fa[v] = 1;
dfsdown(v,u);
sz[u] ++;
f[u] += f[v]+e[i].c;
}
if(sz[u]) f[u] = f[u]/sz[u];
}
void dfsup(int u,int last)
{
for(int i = head[u]; ~i; i = e[i].nxt){
int v = e[i].v;
if(vis[v] || v == last) continue;
g[v] = e[i].c;
if(sz[u] + fa[u] > 1)
g[v] += (f[u]*sz[u] - f[v] - e[i].c + g[u]*fa[u]) /(sz[u]+fa[u]-1);
dfsup(v,u);
}
}
void getcir(int u, int last, int deep)
{
que[deep] = u;
for(int i = head[u];~i; i = e[i].nxt){
int v = e[i].v;
if(v == last) continue;
side[deep] = e[i].c;
if(v == be){
cnt = deep;
flag = 1;
return;
}
getcir(v,u,deep+1);
if(flag) return ;
}
}
int main()
{
scanf("%d%d",&n,&m);
init();
for(int i = 1; i <= n; i++) mo[i] = i;
for(int i = 1; i<= m; i++){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
add(u,v,c);
add(v,u,c);
int mu = getmo(u), mv = getmo(v);
if(mu == mv){
be = mu;
}
mo[mu] = mo[mv];
}
ans = 0;
if(m == n-1){
dfsdown(1,1);
dfsup(1,0);
}
else{
getcir(be,be,1);
for(int i = 1; i <= cnt; i++){
vis[que[i]] = 1;
fa[que[i]] = 2;
}
for(int i = 1; i <= cnt; i++){
que[i+cnt] = que[i];
side[i+cnt] = side[i];
}
for(int i = 1; i <= cnt; i++)
dfsdown(que[i],que[i]);
for(int i = 1; i <= cnt; i++){
double k = 1;
int j;
int u = que[i];
for(j = i+1; j < cnt+i-1; j++){
int v = que[j];
g[u] += k*(side[j-1] + (f[v]*sz[v])/(sz[v]+1));
k/=(sz[v]+1);
}
g[u] += k*(side[j-1]+f[que[j]]);
k = 1;
for(j = i+cnt-1; j > i+1; j--){
int v = que[j];
g[u] += k*(side[j] + (f[v]*sz[v])/(sz[v]+1));
k/=(sz[v]+1);
}
g[u] += k*(side[j]+f[que[j]]);
g[u] /= 2;
}
for(int i = 1; i<= cnt; i++)
dfsup(que[i],que[i]);
}
for(int i = 1; i<= n; i++){
ans += (f[i]*sz[i]+g[i]*fa[i])/(sz[i]+fa[i]);
}
printf("%.5lf\n",ans/n);
return 0;
}