题目描述

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

HINT

Source

分析

如果是树的话,可以向上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]

对于基环树,我们可以拆成一个森林和一个环,其中每棵树的就是环上的点。
我们先从下往上DP,然后再在环上暴力更新环上点的答案,再从上往下更新一遍就好了。

代码

#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);
}

转载于:https://www.cnblogs.com/outerform/p/5921808.html

【基环树DP】[NOI2012]迷失游乐园相关推荐

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

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

  2. 基环树DP(bzoj 1040: [ZJOI2008]骑士)

    树:n个点n-1条边的连通图 基环树:n个点n条边的连通图,也就是一个环套着多棵树 基环树DP:找到环上任意相邻两点,断掉这两点之间的边,就形成了一棵树 之后对这两点分别进行一次树形DP即可 例题: ...

  3. 【暖*墟】#动态规划# 基环树DP的学习与练习

    因为弃置了 四边形不等式优化 ,所以DP的任务还剩下 基环树DP / 插头DP / 动态DP 当然,树形DP / 状压DP / 数位DP / 斜率优化DP 也还是要练习的...... 一 . 基环树的 ...

  4. BZOJ1040 骑士(基环树DP)

    Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各 界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战 ...

  5. bzoj 2878 [Noi2012]迷失游乐园——树上的期望dp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2878 很好的树上概率题的思路,就是分成up和down. 代码中有众多小细节.让我弃疗好几天的 ...

  6. bzoj2878 [Noi2012]迷失游乐园——概率期望DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2878 这个博客写得很好:https://www.cnblogs.com/qt666/p/72 ...

  7. 【BZOJ 2878】 [Noi2012]迷失游乐园

    Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环( ...

  8. acwing-1080. 骑士(基环树dp)

    Z 国的骑士团是一个很有势力的组织,帮会中聚集了来自各地的精英. 他们劫富济贫,惩恶扬善,受到了社会各界的赞扬. 可是,最近发生了一件很可怕的事情:邪恶的 Y 国发起了一场针对 Z 国的侵略战争. 战 ...

  9. 【BZOJ1040】【codevs1423】骑士,第一次的基环外向树DP

    传送门1 传送门2 思路: 好题 比较简单的DP思路 之前没写过基环树DP,第一次搞真心orz 我们发现这些元素是具有从属关系的 也就是说如果对"厌恶的骑士"两两相互连边,那么问题 ...

最新文章

  1. 2020 5月 每日花语
  2. hdu 5178(尺取法)
  3. 最近写的一个qt应用软件
  4. 蓝桥杯java提交格式_2019第十届蓝桥杯JAVA省赛B组
  5. Mozilla Firefox 在用户访问被黑客攻击的网站时发出警告
  6. SimpleAjax 开发包 v3.1 (简单的Ajax)
  7. angular2之pdf文件操作大全
  8. string类有可以调换方向的函数吗_关于String类的split()方法
  9. 模糊数学 计算机智能,吴国平:如果“模糊数学”没有出现,人工智能或许就无从谈起...
  10. 学校实训密码锁设计(基于STC51单片机)报告
  11. 樽海鞘算法(SSA)
  12. 最小采样频率计算公式_AD5933使用外部时钟获得更低的分析频率
  13. android自动修音,唱吧自动一键修音软件-唱吧自动修音app8.8.6 安卓手机版下载_东坡手机下载...
  14. python可视化3d柱状图_「Python实现数据可视化」创建3D柱状图
  15. Python如何打印出26个大写字母和26个小写字母
  16. 虎牙盈利能力得到改善,但监管风险对其收入产生负面影响
  17. 论文研读笔记(三)——基于障碍函数的移动机器人编队控制安全强化学习
  18. 重温了经典电视剧《大时代》
  19. 根据百度地图经纬度获取位置信息
  20. switch开关C语言,C语言开关语句:switch

热门文章

  1. Pyqt 窗体间传值
  2. LoadRunner常见问题整理
  3. 垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
  4. 手把手教你使用ECharts绘制可视化图表
  5. iOS中EXC_BAD_ACCESS解决办法
  6. 【POJ】1742 coins 【背包问题】
  7. 推荐系统的作用和问题
  8. Python 通过ctypes调用 ICTCLAS3.0.DLL
  9. java Reference
  10. 【正一专栏】内马尔要走快走、走好不送!