【总览】

高斯消元基本思想是将方程式的系数和常数化为矩阵,通过将矩阵通过行变换成为阶梯状(三角形),然后从小往上逐一求解。

如:$3X_1 + 2X_2 + 1X_3 = 3$

  $              X_2 + 2X_3 = 1$

  $2X_1 + X_3 = 0$

化为矩阵为:--->----->----->

然后就可以通过最后一行直接求出$X_3 = ...$,将其带回第二行,算出$X_2$,同理算出$X_1$。

代码很好理解:

inline void gauss(){
int i, j, k, l;
for(i = ; i <= n; i++){
l = i;
for(j = i + ; j <= n; j++)
if(fabs(matrix[j][i]) > fabs(matrix[l][i])) l = j;
if(l != i) for(j = i; j <= n + ; j++)
swap(matrix[i][j], matrix[l][j]);
for(j = i + ; j <= n; j++){
double tmp = matrix[j][i] / matrix[i][i];
for(k = i; k <= n + ; k++)
matrix[j][k] -= matrix[i][k] * tmp;
}
}
for(i = n; i >= ; i--){
double t = matrix[i][n + ];
for(j = n; j > i; j--)
t -= ans[j] * matrix[i][j];
ans[i] = t / matrix[i][i];
}
}

高斯消元最常应用在  期望DP  中。下面是几道例题。

期望dp讲解及例题

【BZOJ1013】球形空间产生器sphere

由给出的$n + 1$个坐标,可以列出 $n$个方程,剩下的模板。

【CODE】

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std; const int N = ;
double matrix[N][N], last[N], t, ans[N];
int n; inline int read(){
int i = , f = ; char ch = getchar();
for(; (ch < '' || ch > '') && ch != '-'; ch = getchar());
if(ch == '-') f = -, ch = getchar();
for(; ch >= '' && ch <= ''; ch = getchar())
i = (i << ) + (i << ) + (ch -'');
return i * f;
} inline void wr(int x){
if(x < ) putchar('-'), x = -x;
if(x > ) wr(x / );
putchar(x % + '');
} inline void gauss(){
int i, j, l, k;
for(i = ; i <= n; i++){
l = i;
for(j = i + ; j <= n; j++)
if(fabs(matrix[j][i]) > fabs(matrix[l][i])) l = j;
if(l != i) for(j = i; j <= n + ; j++)
swap(matrix[i][j], matrix[l][j]);
for(j = i + ; j <= n; j++){
double tmp = matrix[j][i] / matrix[i][i];
for(k = i; k <= n + ; k++)
matrix[j][k] -= matrix[i][k] * tmp;
}
}
for(i = n; i >= ; i--){
double tmp = matrix[i][n + ];
for(j = n; j > i; j--)
tmp -= ans[j] * matrix[i][j];
ans[i] = tmp / matrix[i][i];
}
} int main(){
n = read();
for(int i = ; i <= n; i++) scanf("%lf", &last[i]);
for(int i = ; i <= n; i++){
t = ;
for(int j = ; j <= n; j++){
double tmp; scanf("%lf", &tmp);
matrix[i][j] = * (tmp - last[j]);
t += tmp * tmp - last[j] * last[j];
last[j] = tmp;
}
matrix[i][n + ] = t;
}
gauss();
for(int i = ; i <= n; i++){
if(i < n) printf("%.3lf ", ans[i]);
else printf("%.3lf\n", ans[i]);
}
return ;
}

【BZOJ3143】游走

  因为要求期望的最小值,那么走的次数多的边肯定要让花费(编号)尽可能小,所以可以先求出从每个点出发次数的期望值$E_i$,那么对于一条边而言,走这条边的期望次数就是$E_i / degree[i] + E_j / degree[j]$,只要排一遍序就好。

  求点的期望:$E_i = \sum (E_{son[i]} / degree[i])$

【code】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#define eps 1e-10
using namespace std; const int N = ;
double matrix[N][N], ans[N], ret;
int n, m, num, degree[N];
int st[], ed[];
double gg[]; inline void addEdge(const int &u, const int &v){
degree[u]++;
degree[v]++;
st[++num] = u, ed[num] = v;
} inline int read(){
int i = , f = ; char ch = getchar();
for(; (ch < '' || ch > '') && ch != '-'; ch = getchar());
if(ch == '-') f = -, ch = getchar();
for(; ch >= '' && ch <= ''; ch = getchar())
i = (i << ) + (i << ) + (ch -'');
return i * f;
} inline void gauss(){
int i, j, l, k;
for(i = ; i <= n; i++){
l = i;
for(j = i + ; j <= n; j++)
if(fabs(matrix[j][i]) > fabs(matrix[l][i])) l = j;
if(l != i) for(j = i; j <= n + ; j++)
swap(matrix[i][j], matrix[l][j]);
for(j = i + ; j <= n; j++){
double tmp = matrix[j][i] / matrix[i][i];
for(k = i; k <= n + ; k++)
matrix[j][k] -= matrix[i][k] * tmp;
}
}
for(i = n; i >= ; i--){
double tmp = matrix[i][n + ];
for(j = n; j > i; j--)
tmp -= ans[j] * matrix[i][j];
ans[i] = tmp / matrix[i][i];
}
} inline bool cmp (double a, double b){
return a > b;
} int main(){
n = read(), m = read();
for(int i = ; i <= m; i++){
int u = read(), v = read();
addEdge(u, v);
}
int i, j;
for(i = ; i <= m; i++){
matrix[st[i]][ed[i]] += 1.0 /degree[ed[i]];
matrix[ed[i]][st[i]] += 1.0 /degree[st[i]];
}
for(i = ; i <= n; i++) matrix[n][i] = ;
for(i = ; i <= n; i++) matrix[i][i] = -1.0;
matrix[][n + ] = -1.0;
gauss();
for(i = ; i <= m; i++)
gg[i] = ans[st[i]] / degree[st[i]] + ans[ed[i]] / degree[ed[i]];
sort(gg + , gg + m + , cmp);
for(i = ; i <= m; i++) ret += gg[i] * i;
printf("%.3f\n", ret);
return ;
}

【bzoj2337】XOR和路径

  学到了!看见求异或和$----->$按位计算:即一位一位的计算答案每一位上为1的期望值,这样就可以轻松统计出答案。

  每一位都要重新构造矩阵求期望,设$a[i]$表示从$i$到$n$的路径异或和(这一位)为$1$的期望概率(总是≤$1$)

  对于当前第$i + 1$位,若$(dis >> i) \& 1$(这一位为1),那么要异或和为$1$,要求他从关联点异或和为$0$转移来,

  同理,若这一位为$0$,要求从$1$转移来。即:$$a[i] = \sum a[son[i]](dis这一位为0) / degree[i]  + \sum a[son[i]](dis这一位为1) / degree[i]$$。

【code】

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std; const int N = , M = ;
int n, m;
int ecnt, st[M << ], ed[M << ], len[M << ], degree[N];
double matrix[N][N], ans[N], ret; inline void addEdge(const int &u, const int &v, const int &l){
st[++ecnt] = u, ed[ecnt] = v, len[ecnt] = l; degree[u]++;
if(u != v) st[++ecnt] = v, ed[ecnt] = u, len[ecnt] = l, degree[v]++;
} inline void gauss(){
int i, j, k, l;
for(i = ; i <= n; i++){
l = i;
for(j = i + ; j <= n; j++)
if(fabs(matrix[j][i]) > fabs(matrix[l][i])) l = j;
if(l != i) for(j = i; j <= n + ; j++)
swap(matrix[i][j], matrix[l][j]);
for(j = i + ; j <= n; j++){
double tmp = matrix[j][i] / matrix[i][i];
for(k = i; k <= n + ; k++)
matrix[j][k] -= matrix[i][k] * tmp;
}
}
for(i = n; i >= ; i--){
double t = matrix[i][n + ];
for(j = n; j > i; j--)
t -= ans[j] * matrix[i][j];
ans[i] = t / matrix[i][i];
}
} int main(){
scanf("%d%d", &n, &m);
int i, j, k;
for(i = ; i <= m; i++){
int u, v, w; scanf("%d%d%d", &u, &v, &w);
addEdge(u, v, w);
}
for(i = ; i <= ; i++){
memset(matrix, , sizeof matrix);
memset(ans, , sizeof ans);
for(j = ; j <= n; j++) matrix[j][j] = ;
for(j = ; j <= ecnt; j++){
int l = len[j], u = st[j], v = ed[j];
if(u == n) continue;
if((l >> i) & ){
matrix[u][v] += 1.0 / degree[u];
matrix[u][n + ] += 1.0 / degree[u];
}
else matrix[u][v] -= 1.0 / degree[u];
}
gauss();
ret += ans[] * ( << i);
}
printf("%.3f\n", ret);
return ;
}

【高斯消元】兼 【期望dp】例题的更多相关文章

  1. 高斯消元与期望DP

    高斯消元可以解决一系列DP序混乱的无向图上(期望)DP DP序 DP序是一道DP的所有状态的一个排列,使状态x所需的所有前置状态都位于状态x前: (通俗的说,在一个状态转移方程中‘=’左侧的状态应该在 ...

  2. LOJ 2542 「PKUWC2018」随机游走 ——树上高斯消元(期望DP)+最值反演+fmt

    题目:https://loj.ac/problem/2542 可以最值反演.注意 min 不是独立地算从根走到每个点的最小值,在点集里取 min ,而是整体来看,“从根开始走到点集中的任意一个点就停下 ...

  3. HDU4870_Rating_双号从零单排_高斯消元求期望

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4870 原题: Rating Time Limit: 10000/5000 MS (Java/Other ...

  4. hdu 4870 rating(高斯消元求期望)

    Rating Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  5. Luogu3232 HNOI2013 游走 高斯消元、期望、贪心

    传送门 这种无向图上从一个点乱走到另一个点的期望题目好几道与高斯消元有关 首先一个显然的贪心:期望经过次数越多,分配到的权值就要越小. 设$du_i$表示$i$的度,$f_i$表示点$i$的期望经过次 ...

  6. 【BZOJ3143】【HNOI2013】游走 && 【BZOJ3270】博物馆 【高斯消元+概率期望】

    刚学完 高斯消元,我们来做几道题吧! T1:[BZOJ3143][HNOI2013]游走 Description 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小 ...

  7. loj2542 「PKUWC2018」随机游走 MinMax 容斥+树上高斯消元+状压 DP

    题目传送门 https://loj.ac/problem/2542 题解 肯定一眼 MinMax 容斥吧. 然后问题就转化为,给定一个集合 \(S\),问期望情况下多少步可以走到 \(S\) 中的点. ...

  8. 【BZOJ-3143】游走 高斯消元 + 概率期望

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

  9. 【BZOJ-3270】博物馆 高斯消元 + 概率期望

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

  10. [ACM] hdu 4418 Time travel (高斯消元求期望)

    Time travel Problem Description Agent K is one of the greatest agents in a secret organization calle ...

随机推荐

  1. Promise实现多图预加载

    Promise正如它的中文意思“承诺”一样,保存着未来会发生事件(一般为异步操作).Promise避免了“回调地狱”,写法更加接近同步操作.说到同步,我更加喜欢async.await,它们书写更贴近同 ...

  2. PO/VO/POJO/BO/VO图解

  3. mac os 安装PIP 及异常“”Can't install python module: PyCharm Error: “byte-compiling is disabled, skipping”“”的解决方案

    For all who have the same problem, it took me a while to find the solution in a new installation of ...

  4. ThinkPHP3.2 生成二维码

    下面是整合将phpqrcode整合到TP生成二维码就可以解决这个问题了.其实也很简单,使用方法如下:先下载附件解压至ThinkPHP/Extend/Vendor目录,目录不存在自己创建.      v ...

  5. 基于Spring的最简单的定时任务实现与配置(一)

    朋友的项目中有点问题.他那边是Spring架构的,有一个比较简单的需要定时的任务执行.在了解了他的需求之后,于是提出了比较简单的Spring+quartz的实现方式. 注意本文只是讨论,在已搭建完毕的 ...

  6. 关于Javascript循环体变量声明与初始化的效率问题

    针对循环体变量声明与初始化的效率问题,将执行的简单测试代码如下: function test(n) { console.time('Internally initialized'); for (var ...

  7. Scrapy中使用cookie免于验证登录和模拟登录

    Scrapy中使用cookie免于验证登录和模拟登录 引言 python爬虫我认为最困难的问题一个是ip代理,另外一个就是模拟登录了,更操蛋的就是模拟登录了之后还有验证码,真的是不让人省心,不过既然有 ...

  8. ionic 的缓存 和局部刷新

    最近两天在做项目时,发现ionic的缓存功能非常方便好用,提高了再低端手机特别是android比较低版本上的流畅性!可是,后来发现,整体的缓存整个页面并不是一个一劳永逸的办法,结合局部刷新功能,感觉就 ...

  9. 读Zepto源码之属性操作

    这篇依然是跟 dom 相关的方法,侧重点是操作属性的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zepto1.2. ...

  10. java设计模式综合项目实战视频教程

    java设计模式综合项目实战视频教程 视频课程目录如下: 第01节课:本课程整体内容介绍:X-gen系统概况,包括:引入.X-gen项目背景.X-gen的HelloWorld第02节课:X-gen整体 ...