题目描述

传送门

分析

首先判掉 \(INF\) 的情况

第一种情况就是不能从 \(s\) 走到 \(t\)

第二种情况就是从 \(s\) 出发走到了出度为 \(0\) 的点,这样就再也走不到 \(t\)

然后我们去考虑 \(60\) 分的做法

我们设 \(dp[u]\) 为当前在点 \(u\) 走到点 \(t\) 的期望步数

那么就有

\(dp[u]=\sum_{u->v}^v((dp[v]+1) \times \frac{1}{rd[u]})\)

移项之后就变成了

\(dp[u]-\sum_{u->v}^v(dp[v] \times \frac{1}{rd[u]})=1\)

初始化 \(dp[t]=0\)

一共有 \(n\) 个未知数,\(n\)个方程可以用高斯消元解决

这样做时间复杂度是 \(n^3\) 的

下面我们去考虑满分做法

因为保证强连通分量的大小不超过 \(100\)

所以我们可以在强联通分量内使用高斯消元

对于整个 \(DAG\) 使用拓扑排序去解决

注意拓扑排序要建反图

对于拓扑序小于 \(t\) 所属强联通分量的强联通分量,我们没有必要去算

因为在到这些点之前就已经到达了 \(t\)

对于其它的强联通分量

如果分量内的某个点的去边所指向的点在当前的强联通分量中,我们把其作为未知数参与消元

对于不在这个强联通分量中的点,这个点肯定在之前被求出来过

我们把它作为常数

代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
inline int read(){
int x=0,fh=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
typedef double db;
const db eps=1e-8;
const int maxn=1e6+5;
const int maxk=105;
const int maxm=1e4+5;
int head[maxn],tot=1;
struct asd{
int to,next;
}b[maxn],b2[maxn];
void ad(int aa,int bb){
b[tot].to=bb;
b[tot].next=head[aa];
head[aa]=tot++;
}
int h2[maxn],t2=1;
void ad2(int aa,int bb){
b2[t2].to=bb;
b2[t2].next=h2[aa];
h2[aa]=t2++;
}
int rd[maxn];
db mp[maxk][maxk];
int jl[maxk][maxk];
int low[maxn],dfn[maxn],dfnc,js,shuyu[maxn],sta[maxn],top,siz[maxn];
void tar(int now){
dfn[now]=low[now]=++dfnc;
sta[++top]=now;
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(!dfn[u]){
tar(u);
low[now]=std::min(low[now],low[u]);
} else if(!shuyu[u]){
low[now]=std::min(low[now],dfn[u]);
}
}
if(dfn[now]==low[now]){
js++;
while(1){
int y=sta[top--];
shuyu[y]=js;
siz[js]++;
if(y==now) break;
}
}
}
int n,m,s,t,rk[maxm],du[maxm],xh[maxm];
std::vector<int> g[maxn];
db dp[maxn];
bool jud;
void gsxy(int id){
memset(rk,0,sizeof(rk));
memset(xh,0,sizeof(xh));
int ncnt=0;
for(int i=1;i<=n;i++){
if(shuyu[i]==id){
rk[i]=++ncnt;
xh[ncnt]=i;
g[id].push_back(i);
if(i==t) jud=1;
}
}
if(jud==0){
return;
} else {
memset(mp,0,sizeof(mp));
memset(jl,0,sizeof(jl));
for(int i=1;i<=ncnt;i++){
mp[i][ncnt+1]=1;
}
for(int i=0;i<g[id].size();i++){
int now=g[id][i];
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(shuyu[u]==shuyu[now]){
jl[rk[now]][rk[u]]++;
} else {
mp[rk[now]][ncnt+1]+=(double)dp[u]/du[now];
}
}
}
for(int i=0;i<g[id].size();i++){
for(int j=0;j<g[id].size();j++){
int aa=g[id][i],bb=g[id][j];
if(i==j){
mp[rk[aa]][rk[aa]]=(db)(du[aa]-jl[rk[aa]][rk[aa]])/du[aa];
} else {
mp[rk[aa]][rk[bb]]=(db)(-1.0)*jl[rk[aa]][rk[bb]]/du[aa];
}
}
}
for(int i=0;i<g[id].size();i++){
if(g[id][i]==t){
int now=rk[g[id][i]];
for(int j=1;j<=ncnt+1;j++){
mp[now][j]=0;
}
mp[now][now]=1;
}
}
int now=1;
for(int i=1;i<=ncnt;i++){
double mmax=0;
int jl=0;
for(int j=now;j<=ncnt;j++){
if(std::fabs(mp[j][i])>std::fabs(mmax)){
mmax=mp[j][i];
jl=j;
}
}
if(std::fabs(mmax)<eps) continue;
if(jl!=now) std::swap(mp[jl],mp[now]);
for(int j=i+1;j<=ncnt+1;j++){
mp[now][j]/=mp[now][i];
}
mp[now][i]=1.0;
for(int j=now+1;j<=ncnt;j++){
db cs=mp[j][i];
for(int k=i;k<=ncnt+1;k++){
mp[j][k]-=cs*mp[now][k];
}
}
now++;
}
dp[xh[ncnt]]=mp[ncnt][ncnt+1];
for(int i=ncnt-1;i>=1;i--){
dp[xh[i]]=mp[i][ncnt+1];
for(int j=i+1;j<=n;j++){
dp[xh[i]]-=mp[i][j]*dp[xh[j]];
}
}
}
}
std::queue<int> q;
void tp(){
for(int i=1;i<=js;i++){
if(rd[i]==0) q.push(i);
}
while(!q.empty()){
int now=q.front();
gsxy(now);
q.pop();
for(int i=h2[now];i!=-1;i=b2[i].next){
int u=b2[i].to;
rd[u]--;
if(rd[u]==0) q.push(u);
}
}
}
bool vis[maxn];
void dfs(int now){
vis[now]=1;
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(!vis[u]) dfs(u);
}
}
int main(){
memset(h2,-1,sizeof(h2));
memset(head,-1,sizeof(head));
n=read(),m=read(),s=read(),t=read();
for(int i=1;i<=m;i++){
int aa,bb;
aa=read(),bb=read();
ad(aa,bb);
du[aa]++;
}
dfs(s);
if(vis[t]==0){
printf("INF\n");
return 0;
}
for(int i=1;i<=n;i++){
if(i==t) continue;
if(vis[i] && !du[i]){
printf("INF\n");
return 0;
}
}
for(int i=1;i<=n;i++){
if(!dfn[i]) tar(i);
}
for(int i=1;i<=n;i++){
for(int j=head[i];j!=-1;j=b[j].next){
int u=b[j].to;
if(shuyu[i]!=shuyu[u]){
ad2(shuyu[u],shuyu[i]);
rd[shuyu[i]]++;
}
}
}
tp();
printf("%.3f\n",dp[s]);
return 0;
}

l洛谷 P6030 [SDOI2012]走迷宫 概率与期望+高斯消元的更多相关文章

  1. 洛谷 P6030 - [SDOI2012]走迷宫(高斯消元+SCC 缩点)

    题面传送门 之所以写个题解是因为题解区大部分题解的做法都有 bug(u1s1 周六上午在讨论区里连发两个 hack 的是我,由于我被禁言才让 ycx 代发的) 首先碰到这种期望题,我们套路地设 \(d ...

  2. 【BZOJ2707】[SDOI2012]走迷宫 Tarjan+拓扑排序+高斯消元+期望

    [BZOJ2707][SDOI2012]走迷宫 Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,M ...

  3. 洛谷P4457/loj#2513 [BJOI2018]治疗之雨(高斯消元+概率期望)

    题面 传送门(loj) 传送门(洛谷) 题解 模拟赛的时候只想出了高斯消元然后死活不知道怎么继续--结果正解居然就是高斯消元卡常? 首先有个比较难受的地方是它一个回合可能不止扣一滴血--我们得算出\( ...

  4. BZOJ 3143: [Hnoi2013]游走 概率与期望+高斯消元

    Description 一个无向连通图,顶点从1编号到N,边从1编号到M.小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获 ...

  5. BZOJ 3270: 博物馆 概率与期望+高斯消元

    和游走挺像的,都是将概率转成期望出现的次数,然后拿高斯消元来解. #include <bits/stdc++.h> #define N 23 #define setIO(s) freope ...

  6. 洛谷P3265 [JLOI2015]装备购买(线性基+高斯消元)

    传送门 不知道线性基是什么东西的可以看看蒟蒻的总结 不难看出题目讲的就是线性基 这种最小化权值的问题一般都是贪心的,就是按价值从低到高考虑每一个是否能选 据说贪心的证明得用拟阵我不会 据说这题是实数意 ...

  7. BZOJ 1778: [Usaco2010 Hol]Dotp 驱逐猪猡 概率与期望+高斯消元

    这个还挺友好的,自己相对轻松能想出来~令 $f[i]$ 表示起点到点 $i$ 的期望次数,则 $ans[i]=f[i]\times \frac{p}{q}$ #include <cmath> ...

  8. [BZOJ3143][HNOI2013]游走(期望+高斯消元)

    3143: [Hnoi2013]游走 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3576  Solved: 1608[Submit][Status ...

  9. 【BZOJ】3143: [Hnoi2013]游走 期望+高斯消元

    [题意]给定n个点m条边的无向连通图,每条路径的代价是其编号大小,每个点等概率往周围走,要求给所有边编号,使得从1到n的期望总分最小(求该总分).n<=500. [算法]期望+高斯消元 [题解] ...

随机推荐

  1. 跟我一起学.NetCore之日志(Log)模型核心

    前言 鲁迅都说:没有日志的系统不能上线(鲁迅说:这句我没说过,但是在理)!日志对于一个系统而言,特别重要,不管是用于事务审计,还是用于系统排错,还是用于安全追踪.....都扮演了很重要的角色:之前有很 ...

  2. CF1256A Payment Without Change 题解

    OI生涯打的第一场CF比赛,写篇题解纪念一下吧 ------------可以想到先尽量用面值为1的硬币来凑,然后再用面值为n的硬币来补足.先算出用上所有面值为1的硬币还差多少钱,然后判断用面值为n的硬 ...

  3. mysql8.0的下载、安装、可视化软件(下载、安装、破解)

    获取下面相关资源,请关注微信公众号“带你做毕设或者添加小编微信,有不明白的联系小编,可以提供远程帮助哦 mysql压缩版最新版本下载地址https://dev.mysql.com/downloads/ ...

  4. Pyqt QImage 与 np array 转换方法

    Pyqt QImage 与 np array 转换方法(转载) img=cv2.resize(src=img,dsize=None,fx=0.2,fy=0.2) img2=cv2.cvtColor(i ...

  5. python - 平方根格式化 + 字符串分段组合

    题目来源:python123 平方根格式化 描述 获得用户输入的一个整数a,计算a的平方根,保留小数点后3位,并打印输出.‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪ ...

  6. redis数据库基础篇

    一.Redis介绍 Redis 是一个高性能的key-value数据格式的内存缓存,NoSQL数据库.NOSQL:not only sql,泛指非关系型数据库.关系型数据库: (mysql, orac ...

  7. 揭秘 Kubernetes attach/detach controller 逻辑漏洞致使 pod 启动失败

    前言 本文主要通过深入学习k8s attach/detach controller源码,了解现网案例发现的attach/detach controller bug发生的原委,并给出解决方案. 看完本文 ...

  8. RabbitMQ配置文件(rabbitmq.conf)

    rabbitmq.conf配置文件示例: #====================================== #RabbitMQ经纪人部分 #======================= ...

  9. 你懂RocketMQ 的架构原理吗?

    前言 前面我们跟大家聊了聊什么是消息中间件,以及哪些场景使用哪些消息中间件更加合适. 我们了解到RocketMQ是java语言开发的,我们能更深入的阅读源码了解它的底层原理,而且它具有优秀的消息中间件 ...

  10. POJ-2299-Ultra-QuickSort(单点更新 + 区间查询+离散化)

    In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a seque ...