[bzoj2878][NOI2012]迷失遊樂園
2878: [Noi2012]迷失遊樂園
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 894 Solved: 512
[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
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
對於一顆樹的情況,還是比較簡單的。
令
從式子中可以看出,
有了一個環之後,就可以把環先看成一個點,讓這個點做根,求出所有點的
環上的
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100010;
bool flag[N];
struct S{int st,en,va;}aa[N<<1];
int n,m,tot,point[N],next[N<<1],siz[N],c[N],mark,mp[N],fa[N],pre[N],sub[N];
double f[N],g[N],a[30][30];
inline int in(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void add(int x,int y,int z){
next[++tot]=point[x];point[x]=tot;
aa[tot].st=x;aa[tot].en=y;aa[tot].va=z;
next[++tot]=point[y];point[y]=tot;
aa[tot].st=y;aa[tot].en=x;aa[tot].va=z;
}
inline void dp_f(int x,int last){
int i;
for(i=point[x];i;i=next[i])
if(aa[i].en!=last&&flag[aa[i].en]){
dp_f(aa[i].en,x);
f[x]+=f[aa[i].en]+(double)aa[i].va;
++siz[x];fa[aa[i].en]=1;
}
if(siz[x]) f[x]/=(double)siz[x];
}
inline void dp_g(int x,int last,double value){
int i;
if(flag[x]&&siz[last]+fa[last]>1)
g[x]+=(f[last]*(double)siz[last]-f[x]-value+g[last]*fa[last])/(double)(siz[last]+fa[last]-1);
for(i=point[x];i;i=next[i])
if(aa[i].en!=last&&flag[aa[i].en]){
g[aa[i].en]=(double)aa[i].va;
dp_g(aa[i].en,x,(double)aa[i].va);
}
}
inline void find_c(int x,int last){
int i;
for(flag[x]=false,i=point[x];i;i=next[i])
if(aa[i].en!=last){
if(!flag[aa[i].en]){
mark=aa[i].en;
return ;
}
find_c(aa[i].en,x);
if(mark>0){
if(mark==x) mark=-1;
return ;
}
if(mark==-1) break;
}
flag[x]=true;
}
inline void get_c(int x,int last){
int i,o=1;
if(mp[x]) return ;
c[++tot]=x;mp[x]=tot;fa[x]=2;
for(i=point[x];i&&o;i=next[i])
if(aa[i].en!=last&&!flag[aa[i].en]){
pre[aa[i].en]=x;sub[x]=aa[i].en;
get_c(aa[i].en,x);
a[mp[x]][mp[aa[i].en]]=a[mp[aa[i].en]][mp[x]]=(double)aa[i].va;
o=0;
}
}
inline void dp_c(){
int i,u,j;
double mul;
for(i=1;i<=tot;++i){
u=c[i];
for(mul=1,j=sub[u];j!=u;j=sub[j]){
if(sub[j]!=u) g[u]+=mul*(a[mp[pre[j]]][mp[j]]+f[j]*siz[j]/(double)(siz[j]+1));
else g[u]+=mul*(a[mp[pre[j]]][mp[j]]+f[j]);
mul/=(siz[j]+1);
}
for(mul=1,j=pre[u];j!=u;j=pre[j]){
if(pre[j]!=u) g[u]+=mul*(a[mp[sub[j]]][mp[j]]+f[j]*siz[j]/(double)(siz[j]+1));
else g[u]+=mul*(a[mp[sub[j]]][mp[j]]+f[j]);
mul/=(siz[j]+1);
}
g[u]/=2.;
}
}
int main(){
int i,x,y,z;
n=in();m=in();
for(i=1;i<=m;++i){
x=in();y=in();z=in();
add(x,y,z);
}
memset(flag,1,sizeof(flag));
if(m==n-1){
dp_f(1,0);
flag[1]=false;dp_g(1,0,0);
}
else{
find_c(1,0);
for(tot=0,i=1;i<=n;++i)
if(!flag[i]){
get_c(i,0);
break;
}
for(i=1;i<=tot;++i) dp_f(c[i],0);
for(dp_c(),i=1;i<=tot;++i) dp_g(c[i],0,0);
}
double ans=0;
for(i=1;i<=n;++i)
ans+=(f[i]*siz[i]+g[i]*fa[i])/(double)(siz[i]+fa[i]);
printf("%.5f\n",ans/(double)n);
}