同样是高斯消元,我写的版本就受到了歧视

我怎么又犯把 $j$ 打成 $i$ 这种 $sb$ 错误


题意

一张无向图,两个人分别从 $s_1$ 号点和 $s2$ 号点开始,每轮两人都会同时进行一次以下操作:有 $p_i$ 的概率留在原地,剩下的 $1-p_i$ 的概率等概率随机选择一条出边走到连向的点。问两人在每个点相遇的概率(边上不相遇)。

$n\le 20$

题解

首先得知道,这种题的概率就是期望,因为在点 $i$ 相遇($1\le i\le n$)的期望和是 $1$,总概率也是 $1$。

期望和概率的一个重要差别就是期望可以不在 $[0,1]$ 范围内,之后转化的时候记住了。

这种题都有一种特性,就是感觉可以拓扑排序 $dp$。

但拓扑排序只适用于 $DAG$(有向无环图),对于有环图(包括无向图),没法确定 $dp$ 转移顺序。

好了,现在我们降低自己的智商,回到小学状态,想想在小学时你怎么做这种难题。

如果你学过小学奥数(没学过也无所谓吧),应该能想到列方程。

那方程是什么?就是我们的 $dp$ 式子,因为我们只是不确定转移顺序,但式子肯定是对的。

众所周知,方程是互相之间都有约束性的,解必须同时满足所有方程,所以可以解决没法确定转移顺序的情况。

所以这是高斯消元入门题。

由于 $n\le 20$,时间空间都随便用,先不用管会不会爆。

考虑正常 $dp$,设 $f(i,j)$ 表示两人分别在点 $i,j$ 的概率。

那 $f(i,j)$ 可以从它自己所有直接相连的点转移过来。

我们再枚举哪个点转 $x$ 移到点 $i$,哪个点 $y$ 转移到点 $j$。

分类讨论,

当 $i=x,\space j=y$ 时,从 $f(x,y)$ 转移到 $f(i,j)$ 的概率是 $p_x\times p_y$;

当 $i=x,\space j≠y$ 时,从 $f(x,y)$ 转移到 $f(i,j)$ 的概率是 $p_x\times (1-p_y)/du_y$;

当 $i≠x,\space j=y$ 时,从 $f(x,y)$ 转移到 $f(i,j)$ 的概率是 $(1-p_x)\times p_y/du_x$;

当 $i≠x,\space j≠y$ 时,从 $f(x,y)$ 转移到 $f(i,j)$ 的概率是 $(1-p_x)\times (1-p_y)/du_x/du_y$;

其中 $du_x$ 表示点 $x$ 的度(就是有多少个点与它直接相连),注意点 $x$ 自己不算。

我们把所有的 $f(i,j)\space |\space 1\le i\le n,\space 1\le j\le n$ 都看作一个未知数,这样方程组共有 $n^2$ 个未知数,并且我们知道一个未知数表示的二元组(就是两人的位置)到另一个未知数表示的二元组的概率,也就是转移系数(其实就是系数,比如状态 $A$ 有 $k$ 的概率转移到 $B$,方程中就是 $B=kA$)是多少,这样就可以把所有转移系数列成矩阵,解方程组了。

一行方程大概长这样(区分了一下 $i,x$ 和 $j,y$) $$f(i,j) \space =\space f(i,j)\times ... + f(i,y)\times ... + f(x,j)\times ... + f(x,y)\times ...$$

把等号左边的 $f(i,j)$ 移到右边得到 $$0 \space =\space f(i,j)\times ... + f(i,y)\times ... + f(x,j)\times ... + f(x,y)\times ... - f(i,j)$$

也就是对于转移到的状态 $f(i,j)$,它对应的那行方程 等号右边的 $f(i,j)$ 那项的系数先减 $1$。

这个移项处理是高斯消元的终点,把未知数统一移到一边,常数统一移到另一边,省得再判等号两边的未知数。

起点作为被转移项时,其方程的等号左边是 $-1$,因为两人一开始就都在起点,所以已经期望有 $1$ 次到达这种状态,等号右边(所有未知数那边)就加了 $1$,移项到另一边就变成减 $1$。

再注意一点,两人终止的状态不再往其它状态转移,即两人的转移来源点 $x$ 和 $y$ 不能相等。

 #include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x;i<=y;++i)
#define dwn(i,x,y) for(int i=x;i>=y;--i)
#define rep_e(i,u) for(int i=hd[u];i;i=e[i].nxt)
#define ll long long
#define N 22
#define eps 1e-7
using namespace std;
inline int read(){
int x=; bool f=; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=;
for(; isdigit(c);c=getchar()) x=(x<<)+(x<<)+(c^'');
if(f) return x;
return -x;
}
int n,m,a,b;
double p[N],dp[N*N][N*N],ans[N*N];
struct edge{int v,nxt;}e[(N*N)<<];
int hd[N],cnt,du[N];
inline void add(int u,int v){e[++cnt]=(edge){v,hd[u]}, hd[u]=cnt;}
inline int getCnt(int x,int y){return (x-)*n+y;}
bool Gauss(int n){
rep(i,,n){
int r;
//cout<<"wow:"<<i<<endl;
for(r=i; r<=n && fabs(dp[i][r])<eps; ++r); if(fabs(dp[i][r])<eps) return ;
/*
rep(i,1,n){
rep(j,1,n+1) cout<<dp[i][j]<<' ';
cout<<endl;
}*/
if(i^r) swap(dp[i],dp[r]);
/*
rep(i,1,n){
rep(j,1,n+1) cout<<dp[i][j]<<' ';
cout<<endl;
}*/
double div=dp[i][i];
//cout<<div<<endl;
rep(j,i,n+) dp[i][j]/=div;
rep(j,i+,n){
div=dp[j][i];
rep(k,i,n+)
dp[j][k]-=dp[i][k]*div;
}
}
/*
rep(i,1,n){
rep(j,1,n+1) cout<<dp[i][j]<<' ';
cout<<endl;
}*/
ans[n]=dp[n][n+];
dwn(i,n-,){
ans[i]=dp[i][n+];
rep(j,i+,n) ans[i]-=ans[j]*dp[i][j];
}
/*
rep(i,1,n){
ans[i]=dp[fd][n+1]/dp[fd][fd];
}*/
return ;
}
int main(){
n=read(),m=read(),a=read(),b=read();
int u,v,all=n*n;
rep(i,,n) add(i,i);
rep(i,,m)
u=read(),v=read(),
++du[u],++du[v],
add(u,v),add(v,u);
rep(i,,n)
cin>>p[i];
dp[getCnt(a,b)][all+]=-;
rep(i,,n)
rep(j,,n){
int cnt1=getCnt(i,j);
--dp[cnt1][cnt1]; //i=j时自己不能转移到自己,所以自己给自己的转移的期望次数-1
rep_e(ii,i)
rep_e(jj,j){
int x=e[ii].v, y=e[jj].v;
//cout<<"try:"<<i<<' '<<j<<' '<<x<<' '<<y<<endl;
if(x^y){
int cnt2=getCnt(x,y);
if(i==x && j==y) dp[cnt1][cnt2]+=p[i]*p[j];
else if(i==x) dp[cnt1][cnt2]+=p[i]*(-p[y])/du[y];
else if(j==y) dp[cnt1][cnt2]+=(-p[x])*p[j]/du[x];
else dp[cnt1][cnt2]+=(-p[x])*(-p[y])/du[x]/du[y];
//cout<<i<<' '<<j<<' '<<x<<' '<<y<<' '<<cnt1<<' '<<cnt2<<' '<<p[x]<<' '<<p[y]<<' '<<du[x]<<' '<<du[y]<<' '<<dp[cnt1][cnt2]<<endl;
}
}
} if(!Gauss(all)){printf("I AK IOI!\n"); return -;}
rep(i,,n) printf("%.6lf ",ans[getCnt(i,i)]);
return ;
}
/*
3 2 1 3
1 2
2 3
0.5
0.5
0.5
显然,ans[1]和ans[3]应该相等,否则就是程序写错了
*/

怎么网上那么多人写的代码都一个样(包括高斯消元部分),这么不求上进的吗?

我写的高斯消元跟他们不一样,一开始结果不对,我还以为我的高斯消元是错的。

后来调对了,才意识到只是被鄙视了而已,因为我跟其他人写的都不一样。

然后呢?

【bzoj3270】博物馆的更多相关文章

  1. BZOJ3270: 博物馆

    3270: 博物馆 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 269  Solved: 147[Submit][Status][Discuss] ...

  2. BZOJ3270:博物馆(高斯消元)

    Description 有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆.这座博物馆有着特别的样式.它包含由m条走廊连接的n间房间,并且满足可以从任何一 ...

  3. BZOJ3270 博物馆(高斯消元+概率期望)

    将两个人各自所在点视为状态,新建一个图.到达某个终点的概率等于其期望次数.那么高斯消元即可. #include<iostream> #include<cstdio> #incl ...

  4. BZOJ3270: 博物馆【概率DP】【高斯消元】

    Description 有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆.这座博物馆有着特别的样式.它包含由m条走廊连接的n间房间,并且满足可以从任何一 ...

  5. 【概率dp 高斯消元】bzoj3270: 博物馆

    一类成环概率dp的操作模式 Description 有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆.这座博物馆有着特别的样式.它包含由m条走廊连接的n ...

  6. bzoj3270 博物馆(期望+高斯消元)

    Time Limit: 30 Sec  Memory Limit: 128 MB 有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆.这座博物馆有着特别的 ...

  7. [bzoj3270] 博物馆 [期望+高斯消元]

    题面 传送门 思路 本题的点数很少,只有20个 考虑用二元组$S=(u,v)$表示甲在$u$点,乙在$v$点的状态 那么可以用$f(S)$表示状态$S$出现的概率 不同的$f$之间的转移就是通过边 转 ...

  8. bzoj3270博物馆——期望概率DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3270 设计一个状态表示两个人分别在两个点的状态,带个标号num[i][j]: 据此得到状态之 ...

  9. OI刷题录——hahalidaxin

    16-3-25  —— bzoj 2049 [Sdoi2008]Cave 洞穴勘测:LCT入门 bzoj 2002 [Hnoi2010]Bounce 弹飞绵羊:LCT Tsinsen A1303. t ...

  10. 【BZOJ3270】博物馆 期望DP+高斯消元

    [BZOJ3270]博物馆 Description 有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆.这座博物馆有着特别的样式.它包含由m条走廊连接的n ...

随机推荐

  1. JAVA并发编程:相关概念及VOLATILE关键字解析

    一.内存模型的相关概念 由于计算机在执行程序时都是在CPU中运行,临时数据存在主存即物理内存,数据的读取和写入都要和内存交互,CPU的运行速度远远快于内存,会大大降低程序执行的速度,于是就有了高速缓存 ...

  2. [转]C++中sizeof(struct)怎么计算?

    版权属于原作者,我只是排版. 1. sizeof应用在结构上的情况 请看下面的结构: struct MyStruct{ double dda1; char dda; int type;}; 对结构My ...

  3. sklearn 学习之分类树

    概要 基于 sklearn 包自带的 iris 数据集,了解一下分类树的各种参数设置以及代表的意义.   iris 数据集介绍 iris 数据集包含 150 个样本,对应数据集的每行数据,每行数据包含 ...

  4. CPP-基础:extern"C"

    简介:extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的:其次,被它修饰的目标是“C”的.让我们来详细解读这两重含义. 含义: 1.被e ...

  5. 第三单元OO总结

  6. cocos2dx 单张图片加密

    cocos2dx 已经封装好读取加密的prv文件的方法,打开texturepacker,导入一张图片,在content protection中写入密钥,在texture format中选择prv格式 ...

  7. win8/10 bcdboot引导修复命令的原理和使用方法

    win8/10 bcdboot引导修复命令的原理和使用方法 [迅维网原创文章禁止转载] (本文所述已用UEFI+GPT.BIOS+MBR,WIN10 64位企业版和专业版测试过) 在win8/10系统 ...

  8. this经典试题

    <body> <div class="container"> <h3>输出内容</h3> <pre> var name ...

  9. C语言程序运行

    vs2013编辑器 c程序的运行   一.启动Microsoft Visual C++  2013版.新建项目 . 1.  文件——> 新建——> 项目.       2. 确定之后 弹出 ...

  10. 洛谷 2387/BZOJ 3669 魔法森林

    3669: [Noi2014]魔法森林 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 3765  Solved: 2402[Submit][Statu ...