高斯消元小小结

所谓高斯消元,就是一种解线性方程组的算法。

学过线性代数的同学都知道,线性方程组本质就是一个向量X1左乘一个系数矩阵A得到另一个向量X2,我们要求解的就是所有未知数构成的向量X1

设一个n元一次方程组,我们把所有未知数的系数以及等号右边的常数保持相对位置不变的情况下组成一个nn+1列的矩阵,

a11 a12 a13 ...... a1n b1
a21 a22 a23 ...... a2n b2
...
...
an1 an2 an3 ...... ann bn

然后我们通过矩阵的初等变换,每个方程选择一个未知数的系数(我们称为主元),然后把其余方程同一个未知数的系数变为0,最终将该矩阵的未知数系数部分变成每行只有一个非零的数每列只有一个非零的数的鬼畜矩阵,这样很显然每个未知数最终的值都可以直接求出来啦。

当然这里有两个问题

一是精度误差。众所周知浮点数会有精度误差的,精度要依题而定。精度过小会导致较小的系数误以为0,而精度过大则可能导致本该为0的误判为不为0,故而精度要有把握,一般在1e-4~1e-10

二是主元的选择,我们要想办法避免或者减少精度误差,我们可以选择一个方程里系数最大的那个作为主元,这样的精度误差可以减少,因为在浮点数除法运算时,一个较大的数除以一个较小的数的误差是个玄学大。

枚举行,先扫一遍得到该行系数最大值,再枚举剩下(n-1)行,然后对每行n个数进行运算,故而高斯消元的时间复杂度就是O(n3

最后这个方程组如果是在模2的意义下的话,也就是说方程未知数的系数以及等号右边的数不是0就是1的话,我们可以用bitset来加快对每行的运算操作从而时间复杂度降为而O(n2)

洛谷P3389——高斯消元法模板题

 1 #include <algorithm>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cstdio>
 5 #include <iostream>
 6 #include <cmath>
 7 #include <ctime>
 8 #include <queue>
 9 #define MIN(a,b) (((a)<(b)?(a):(b)))
10 #define MAX(a,b) (((a)>(b)?(a):(b)))
11 #define ABS(a) (((a)>0?(a):-(a)))
12 #define debug(a) printf("a=%d\n",a)
13 #define OK cout<<"QAQ"<<endl
14 #define fo(i,a,b) for (int i=(a);i<=(b);++i)
15 #define fod(i,a,b) for (int i=(a);i>=(b);--i)
16 #define rep(i,a,b) for (int i=(a);i<(b);++i)
17 #define red(i,a,b) for (int i=(a);i>(b);--i)
18 #define N 106
19 typedef long long LL;
20 using namespace std;
21 int n, w[N];  //w数组记录第i行最大系数的位置
22 double v[N], a[N][N + 1];  //v数组记录xi的解,a数组为相应矩阵
23 void readint(int& x) {
24     x = 0;
25     char c;
26     int w = 1;
27     for (c = getchar(); c<‘0‘ || c>‘9‘; c = getchar())
28         if (c == ‘-‘) w = -1;
29     for (; c >= ‘0‘ && c <= ‘9‘; c = getchar())
30         x = (x << 3) + (x << 1) + c - ‘0‘;
31     x *= w;
32 }
33 void readlong(long long& x) {
34     x = 0;
35     char c;
36     long long w = 1;
37     for (c = getchar(); c<‘0‘ || c>‘9‘; c = getchar())
38         if (c == ‘-‘) w = -1;
39     for (; c >= ‘0‘ && c <= ‘9‘; c = getchar())
40         x = (x << 3) + (x << 1) + c - ‘0‘;
41     x *= w;
42 }
43 int read() {
44     int x = 0;
45     char c;
46     int w = 1;
47     for (c = getchar(); c<‘0‘ || c>‘9‘; c = getchar())
48         if (c == ‘-‘) w = -1;
49     for (; c >= ‘0‘ && c <= ‘9‘; c = getchar())
50         x = (x << 3) + (x << 1) + c - ‘0‘;
51     x *= w;
52     return x;
53 }
54 bool gauss() {
55     int p;  //p为最大系数的位置
56     double mx = 0;  //mx为最大系数
57     double eps = 1e-6;  //eps为精度控制
58     fo(i, 1, n) {
59         p = 0;
60         mx = 0;
61         fo(j, 1, n) if (fabs(a[i][j]) - eps > mx) { mx = fabs(a[i][j]); p = j; } //fabs函数是浮点数的绝对值函数
62         if (p == 0) return 0;   //这个情况下,该行未知数系数全为0,若等号右边的常数不为0,则该方程组无解,若为0,则有无数组解
63         fo(j, 1, n)
64             if (i != j) {   //枚举其他行进行运算
65                 double qwq = a[j][p] / a[i][p];   //主元选最大的可以在作商时相对地减少精度误差
66                 fo(k, 1, n + 1) a[j][k] -= qwq * a[i][k];   //注意这里是n+1
67             }
68         w[i] = p;
69     }
70     fo(i, 1, n) v[w[i]] = a[i][n + 1] / a[i][w[i]];
71     return 1;
72 }
73 int main() {   // by Lanly
74     readint(n);
75     fo(i, 1, n) fo(j, 1, n + 1) a[i][j] = read();
76     //fo(i, 1, n) fo(j, 1, n + 1) printf("%.2lf%c", a[i][j], j == n + 1 ? ‘\n‘ : ‘ ‘);
77     if (gauss()) fo(i, 1, n) printf("%.2lf\n", v[i]);
78     else puts("No Solution");
79     return 0;
80 }

神奇的代码

原文地址:https://www.cnblogs.com/Lanly/p/11560151.html

时间: 2024-11-05 22:43:58

高斯消元小小结的相关文章

POJ SETI 高斯消元 + 费马小定理

http://poj.org/problem?id=2065 题目是要求 如果str[i] = '*'那就是等于0 求这n条方程在%p下的解. 我看了网上的题解说是高斯消元 + 扩展欧几里德. 然后我自己想了想,就用了高斯消元 + 费马小定理.因为%p是质数,所以很容易就用上了费马小定理,就是在除法的时候用一次就好了.还有就是两个模数相乘还要模一次. #include <cstdio> #include <cstdlib> #include <cstring> #inc

小结:高斯消元

对于一组多项式方程(增广矩阵中,x[i, n+1]表示式子的值:x[i,j]表示第i个方程第j项的系数,在这里,增广矩阵可能不一定是n个,可能多可能少:opt表示运算规则): (x[1,1]*a[1]) opt (x[1,2]*a[2]) opt ... opt (x[1,n]*a[n])=x[1, n+1] (x[2,1]*a[1]) opt (x[2,2]*a[2]) opt ... opt (x[2,n]*a[n])=x[2, n+1] ... (x[n,1]*a[1]) opt (x[n

高斯消元小结

这里只是丢了一个板子,毕竟高斯消元这个东西原理说起来很简单,就是模拟了普通人手工解方程的过程,还是直接上代码来的方便 一道模板题:luogu2455 (在这里不推荐luogu的模板题,数据过水,此题数据强度还可以需要适当的和精度搏斗) 主要提一下判断无解和无穷解的情况 一般的高斯消元是给出\(n\)个方程求\(n\)个未知数的解,但是有的时候会出现给出方程重复(\(x+y=2,2x+2y=4\))或者方程矛盾(\(x+y=2,2x+2y=2\)),这个时候我们进行高斯消元的话,最后的一个(或几个

【BZOJ 4171】 4171: Rhl的游戏 (高斯消元)

4171: Rhl的游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 74  Solved: 33[Submit][Status][Discuss] Description RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色 .每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子 ),黑变白,白变黑.RHL希望把所有格子都变成白色的.不幸

[BZOJ 3143][Hnoi2013]游走(高斯消元+期望)

Description 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数.当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和. 现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小. Solution 对于点u(u≠1):到达u的概率 f[u]=∑f[v]/d[v] (Edges(u,v)) 而f[1]=∑f[v]/d[v]+1

bzoj 2707 [SDOI2012]走迷宫(SCC+高斯消元)

Description Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的有向边,到达另一个点.这样,Morenan走的步数可能很长,也可能是无限,更可能到不了终点.若到不了终点,则步数视为无穷大.但你必须想方设法求出Morenan所走步数的期望值. Input 第1行4个整数,N,M,S,T 第[2, M+1]行每行两个整数o1, o2,表示有一条从o

BZOJ 1770 [Usaco2009 Nov]lights 燈 【高斯消元】

Description 貝希和她的閨密們在她們的牛棚中玩遊戲.但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了.貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望.她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續快樂地跟她的閨密們繼續玩遊戲! 牛棚中一共有N(1 <= N <= 35)盞燈,編號為1到N.這些燈被置於一個非常複雜的網絡之中.有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈. 每盞燈上面都帶有一個開關.當

BZOJ 2844 albus就是要第一个出场 ——高斯消元 线性基

[题目分析] 高斯消元求线性基. 题目本身不难,但是两种维护线性基的方法引起了我的思考. 1 2 3 4 5 6 7 8 9 10 11 12 void gauss(){     k=n;     F(i,1,n){         F(j,i+1,n) if (a[j]>a[i]) swap(a[i],a[j]);         if (!a[i]) {k=i-1; break;}         D(j,30,0) if (a[i]>>j & 1){            

ACM学习历程—HDU 3949 XOR(xor高斯消元)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3949 题目大意是给n个数,然后随便取几个数求xor和,求第k小的.(重复不计算) 首先想把所有xor的值都求出来,对于这个规模的n是不可行的. 然后之前有过类似的题,求最大的,有一种方法用到了线性基. 那么线性基能不能表示第k大的呢? 显然,因为线性基可以不重复的表示所有结果.它和原数组是等价的. 对于一个满秩矩阵 100000 010000 001000 000100 000010 000001