【基环树DP】[NOI2012]迷失游乐园
題目描述
Description
放假了,小Z覺(jué)得呆在家里特別無(wú)聊,于是決定一個(gè)人去游樂(lè)園玩。進(jìn)入游樂(lè)園后,小Z看了看游樂(lè)園的地圖,發(fā)現(xiàn)可以將游樂(lè)園抽象成有n個(gè)景點(diǎn)、m條道路的無(wú)向連通圖,且該圖中至多有一個(gè)環(huán)(即m只可能等于n或者n-1)。小Z現(xiàn)在所在的大門(mén)也正好是一個(gè)景點(diǎn)。小Z不知道什么好玩,于是他決定,從當(dāng)前位置出發(fā),每次隨機(jī)去一個(gè)和當(dāng)前景點(diǎn)有道路相連的景點(diǎn),并且同一個(gè)景點(diǎn)不去兩次(包括起始景點(diǎn))。貪玩的小Z會(huì)一直游玩,直到當(dāng)前景點(diǎn)的相鄰景點(diǎn)都已經(jīng)訪問(wèn)過(guò)為止。小Z所有經(jīng)過(guò)的景點(diǎn)按順序構(gòu)成一條非重復(fù)路徑,他想知道這條路徑的期望長(zhǎng)度是多少?小Z把游樂(lè)園的抽象地圖畫(huà)下來(lái)帶回了家,可是忘了標(biāo)哪個(gè)點(diǎn)是大門(mén),他只好假設(shè)每個(gè)景點(diǎn)都可能是大門(mén)(即每個(gè)景點(diǎn)作為起始點(diǎn)的概率是一樣的)。同時(shí),他每次在選擇下一個(gè)景點(diǎn)時(shí)會(huì)等概率地隨機(jī)選擇一個(gè)還沒(méi)去過(guò)的相鄰景點(diǎn)。
Input
第一行是兩個(gè)整數(shù)n和m,分別表示景點(diǎn)數(shù)和道路數(shù)。 接下來(lái)行,每行三個(gè)整數(shù)Xi, Yi, Wi,分別表示第i條路徑的兩個(gè)景點(diǎn)為Xi, Yi,路徑長(zhǎng)Wi。所有景點(diǎn)的編號(hào)從1至n,兩個(gè)景點(diǎn)之間至多只有一條道路。
Output
?共一行,包含一個(gè)實(shí)數(shù),即路徑的期望長(zhǎng)度,保留五位小數(shù)
Sample Input
4 3
1 2 3
2 3 1
3 4 4
Sample Output
6.00000
【樣例解釋】樣例數(shù)據(jù)中共有6條不同的路徑: 路徑 長(zhǎng)度 概率
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
因此期望長(zhǎng)度 = 8/4 + 3/8 + 5/8 + 4/8 + 4/8 + 8/4 = 6.00
【評(píng)分方法】本題沒(méi)有部分分,你程序的輸出只有和標(biāo)準(zhǔn)答案的差距不超過(guò)0.01時(shí),才能獲得該測(cè)試點(diǎn)的滿分,否則不得分。
【數(shù)據(jù)規(guī)模和約定】對(duì)于100%的數(shù)據(jù),1 <= Wi <= 100。 測(cè)試點(diǎn)編號(hào) n m 備注
1 n=10 m = n-1 保證圖是鏈狀
2 n=100 只有節(jié)點(diǎn)1的度數(shù)大于2
3 n=1000 /
4 n=100000 /
5 n=100000 /
6 n=10 m = n /
7 n=100 環(huán)中節(jié)點(diǎn)個(gè)數(shù)<=5
8 n=1000 環(huán)中節(jié)點(diǎn)個(gè)數(shù)<=10
9 n=100000 環(huán)中節(jié)點(diǎn)個(gè)數(shù)<=15
10 n=100000 環(huán)中節(jié)點(diǎn)個(gè)數(shù)<=20
HINT
Source
分析
如果是樹(shù)的話,可以向上DP一次,再向下DP一次求出解。
up:f[u]=∑f[u.son]degree[u]?(u==root)down:f[u.son]=(f[u]?f[u.son]×degree[u]?1degree[u])÷degree[u]?1degree[u]+f[u.son]
對(duì)于基環(huán)樹(shù),我們可以拆成一個(gè)森林和一個(gè)環(huán),其中每棵樹(shù)的就是環(huán)上的點(diǎn)。
我們先從下往上DP,然后再在環(huán)上暴力更新環(huán)上點(diǎn)的答案,再?gòu)纳贤赂乱槐榫秃昧恕?/p>
代碼
#include<cstdio> #include<algorithm> #define MAXN 100000 using namespace std; int n,m,d[MAXN+10],bgcir,cir[MAXN+10],cnt; double f[MAXN+10],ans,ff[MAXN+10],g[MAXN+10]; bool vis[MAXN+10]; void Read(int &x){char c;while(c=getchar(),c!=EOF)if(c>='0'&&c<='9'){x=c-'0';while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';ungetc(c,stdin);return;} } struct node{int v,wt;bool vis;node *next,*back; }*adj[MAXN+10],edge[MAXN*2+10],*ecnt=edge,*pre[MAXN+10]; inline void addedge(int u,int v,int wt){node *p=++ecnt;p->v=v;p->wt=wt;p->next=adj[u];adj[u]=p;p->vis=0;p=p->back=++ecnt;p->v=u;p->wt=wt;p->next=adj[v];adj[v]=p;p->vis=0;p->back=ecnt-1; } void read(){Read(n),Read(m);int i,u,v,wt;for(i=1;i<=m;i++){Read(u),Read(v),Read(wt);d[u]++,d[v]++;addedge(u,v,wt);} } void dfs(int u,int fa){for(node *p=adj[u];p;p=p->next){if(p->v!=fa&&!p->vis){dfs(p->v,u);f[u]+=f[p->v]+p->wt;}}if(fa){if(d[u]>1)f[u]/=d[u]-1;}else{if(d[u])f[u]/=d[u];} } void dfs2(int u,int fa){for(node *p=adj[u];p;p=p->next){if(p->v!=fa&&!p->vis){if(d[u]>1)f[p->v]=((f[u]-(f[p->v]+p->wt)/d[u])/(d[u]-1)*d[u]+p->wt)/d[p->v]+f[p->v]/d[p->v]*(d[p->v]-1);elsef[p->v]=1.0*p->wt/d[p->v]+f[p->v]/d[p->v]*(d[p->v]-1);dfs2(p->v,u);}} } void solve(){dfs(1,0);dfs2(1,0);for(int i=1;i<=n;i++)ans+=f[i];ans/=n; } void find_cir(int u){if(vis[u]){bgcir=u;return;}vis[u]=1;for(node *p=adj[u];p;p=p->next){if(!p->vis){p->back->vis=p->vis=1;pre[p->v]=p;find_cir(p->v);}} } void solve2(){find_cir(1);int i=bgcir,j;for(node *p=edge;p<=ecnt;p++)p->vis=0;do{cir[++cnt]=i;pre[i]->vis=pre[i]->back->vis=1;i=pre[i]->back->v;}while(i!=bgcir);for(i=1;i<=cnt;i++){cir[i+cnt]=cir[i];d[cir[i]]-=2;dfs(cir[i],0);d[cir[i]]+=2;}for(i=1;i<=cnt;i++){g[cir[i+cnt-1]]=f[cir[i+cnt-1]];for(j=i+cnt-2;j>i;j--)g[cir[j]]=(g[cir[j+1]]+pre[cir[j]]->wt)/(d[cir[j]]-1)+f[cir[j]]/(d[cir[j]]-1)*(d[cir[j]]-2);g[cir[i]]=(g[cir[i+1]]+pre[cir[i]]->wt)/d[cir[i]];g[cir[i+1]]=f[cir[i+1]];for(j=i+2;j<i+cnt;j++)g[cir[j]]=(g[cir[j-1]]+pre[cir[j-1]]->wt)/(d[cir[j]]-1)+f[cir[j]]/(d[cir[j]]-1)*(d[cir[j]]-2);g[cir[i]]+=(g[cir[i+cnt-1]]+pre[cir[i+cnt-1]]->wt)/d[cir[i]];ff[cir[i]]=g[cir[i]]+f[cir[i]]/d[cir[i]]*(d[cir[i]]-2);}for(i=1;i<=cnt;i++){f[cir[i]]=ff[cir[i]];dfs2(cir[i],0);}for(i=1;i<=n;i++){ans+=f[i];}ans/=n; } int main() {read();if(m==n-1)solve();elsesolve2();printf("%.5lf\n",ans); }轉(zhuǎn)載于:https://www.cnblogs.com/outerform/p/5921808.html
總結(jié)
以上是生活随笔為你收集整理的【基环树DP】[NOI2012]迷失游乐园的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java中判断Object对象类型
- 下一篇: Java 笔试题集锦