zoukankan      html  css  js  c++  java
  • 算法初探

    更新记录

    【1】2020.07.30-16:36

    • 1.完善内容

    前言

    千万不要将行的意义和列的意义搞混!!!

    正文

    以下称为矩阵的初等行变换

    • 用非零的数乘某一行
    • 交换两行的位置
    • 将其中一行的若干倍加到另一行上

    也就是说,高斯消元就是通过初等行变换去求解变化为增广矩阵的线性方程组

    例如下面这个方程组:

    (egin{cases}2x_0+x_1+5x_2+x_3=23\-x_0+2x_1+8x_2-4x_3=11\3x_0+x_1-x_2+2x_3=10\x_0+6x_1+x_2x_3=20end{cases})

    我们把它写成增广矩阵的形式就是:

    (egin{bmatrix}2&1&5&1&23\-1&2&8&-4&11\3&1&-1&2&10\1&6&1&1&20end{bmatrix})

    那么如何求解这个方程组呢?

    普通的就是进行加减消元,之后将每个解写成 (kx_n=y) 的形式
    那么高斯消元就是通过将增广矩阵进行初等行变换求解

    变换过程:

    (egin{bmatrix}0&-11&3&-1&-17\0&8&9&-3&31\0&-17&-4&-1&-50\1&6&1&1&20end{bmatrix})

    (egin{bmatrix}1&6&1&1&20\0&-11&3&-1&-17\0&8&9&-3&31\0&-17&-4&-1&-50end{bmatrix})

    (egin{bmatrix}1&6&1&1&20\0&1&-dfrac{3}{11}&dfrac{1}{11}&dfrac{17}{11}\0&8&9&-3&31\0&-17&-4&-1&-50end{bmatrix})

    (egin{bmatrix}1&0&dfrac{29}{11}&dfrac{5}{11}&dfrac{118}{11}\0&1&-dfrac{3}{11}&dfrac{1}{11}&dfrac{17}{11}\0&0&dfrac{123}{11}&-dfrac{41}{11}&dfrac{205}{11}\0&0&-dfrac{95}{11}&dfrac{6}{11}&-dfrac{261}{11}end{bmatrix})

    (egin{bmatrix}1&0&dfrac{29}{11}&dfrac{5}{11}&dfrac{118}{11}\0&1&-dfrac{3}{11}&dfrac{1}{11}&dfrac{17}{11}\0&0&dfrac{3}{11}&-dfrac{1}{11}&dfrac{5}{11}\0&0&-dfrac{95}{11}&dfrac{6}{11}&-dfrac{261}{11}end{bmatrix})

    (egin{bmatrix}1&0&0&dfrac{4}{3}&dfrac{19}{3}\0&1&0&0&2\0&0&1&-dfrac{1}{3}&dfrac{5}{3}\0&0&0&-dfrac{7}{3}&dfrac{28}{3}end{bmatrix})

    (egin{bmatrix}1&0&0&dfrac{4}{3}&dfrac{19}{3}\0&1&0&0&2\0&0&1&-dfrac{1}{3}&dfrac{5}{3}\0&0&0&1&4end{bmatrix})

    (egin{bmatrix}1&0&0&0&1\0&1&0&0&2\0&0&1&0&3\0&0&0&1&4end{bmatrix})

    解得(对不起我选的例子不太好计算,但是上面的过程我是一步步计算来的QAQ):

    (egin{cases}x_0=1\x_1=2\x_2=3\x_3=4end{cases})

    所以就解得了

    那么用来代码来写就是:

    [SDOI2006]线性方程组

    为啥不用模板呢?因为模板数据太弱了
    这道题也是板子,相比于模板加了无解的判断

    因为会存在某些毒瘤卡行的数据,所以我们一切小心
    不信你可以试试下面这个数据

    in:
    2
    0 2 3
    0 0 0
    
    out:0
    

    最外面的循环i控制消元的列数

    (np)则是选择这一列系数不为(0)的一个

    因为前(i)个都已经进行过消元了嘛,所以一开始我写的是(np=i)
    但是这就没有想到前(i)个会出现无解或无穷解的情况

    所以当出现无解或无穷解的情况时,我们操作不变,看下一,用变量(line)统计

    然后循环(line+1 o n)发现系数不为零的就选它,为了方便实现,我们一般取最大值
    至于取绝对值的原因是有可能方程组的系数集合里面没有正数

    判断系数是否为零,不是就让这一行回到该到的位置

    后面就全是初等行变换进行加减消元了

    循环出来之后,看看这个(line)是否小于等于(n)

    如果是,就说明了存在系数为0的情况
    必然是无解或者无穷解

    循环看看(n+1),也就是等式的结果是否为零,如果不是,无解
    没有无解就肯定是无穷解啦

    最后输出来个判断,防止出现(-0.00)的情况

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,np,line=1,y;
    double c,eps=1e-16;
    struct matrix{
    	double ele[10010];
    }m[10010];
    inline double abs(double a) {return a>0?a:-a;}
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		for(int o=1;o<=n+1;o++)
    			scanf("%lf",&m[i].ele[o]);
    	for(int i=1;i<=n;i++){
    		np=line;
    		for(int o=line+1;o<=n;o++)
    			if(abs(m[o].ele[i])>abs(m[np].ele[i]))
    				np=o;
    		if(!m[np].ele[i]) continue;
    		swap(m[i],m[np]);
    		for(int o=1;o<=n;o++){
    			if(o!=line&&m[o].ele[i]){
    				c=m[o].ele[i]/m[i].ele[i];
    				for(int p=i+1;p<=n+1;p++){
    					m[o].ele[p]-=c*m[i].ele[p];
    				}
    			}
    		}
    		line+=1;
    	}
    	if(line<=n){
    		for(int i=line;i<=n;i++){
    			if(m[line].ele[n+1]){
    				printf("-1
    ");
    				return 0;
    			}
    		}
    		printf("0
    ");
    		return 0;
    	}
    	for(int i=1;i<=n;i++){
    		printf("x%d=%.2lf
    ",i,abs(m[i].ele[n+1]/m[i].ele[i])<eps?0:m[i].ele[n+1]/m[i].ele[i]);
    	}
    }
    

    [JSOI2008]球形空间产生器

    比那动态规划好写多了

    看题就能发现,这就是高斯消元的裸题
    难点在于如何写出增广矩阵

    设每个点为 (a_1,a_2,dots,a_{n+1})
    每个点的坐标为(以 (a_1) 为例) (a_{1,1},a_{1,2},dots,a_{1,n})

    球心的坐标为 (b_1,b_2,dots ,b_n)

    分析题目,每个点到球心的距离相等,也就是说:
    (sumlimits_{i=1}^n (a_{1,i}-b_i)^2=sumlimits_{i=1}^n (a_{2,i}-b_i)^2=dots =sumlimits_{i=1}^n (a_{n+1,i}-b_i)^2)

    我们将每个等号两边的式子作差,就会得到(k=n)个等式:
    (sumlimits_{i=1}^n (a_{k,i}-b_i)^2-(a_{k+1,i}-b_i)^2=0)

    (sumlimits_{i=1}^n [a_{k,i}^2-a_{k+1,i}^2-2b_i(a_{k,i}-a_{k+1,i})]=0)

    因为只有 (b_i) 是未知数,所以我们化为 (kb_i=y) 的形式:

    (sumlimits_{i=1}^n 2b_i(a_{k,i}-a_{k+1,i})=sumlimits_{i=1}^n (a_{k,i}^2-a_{k+1,i}^2))

    清晰明了,所以增广矩阵为:

    (egin{bmatrix}2(a_{1,1}-a_{2,1})&2(a_{1,2}-a_{2,2})&cdots&2(a_{1,n}-a_{2,n})&sumlimits_{i=1}^n (a_{1,i}^2-a_{2,i}^2)\2(a_{2,1}-a_{3,1})&2(a_{2,2}-a_{3,2})&cdots&2(a_{2,n}-a_{3,n})&sumlimits_{i=1}^n (a_{2,i}^2-a_{3,i}^2)\vdots&vdots&ddots&vdots&vdots\2(a_{n,1}-a_{n+1,1})&2(a_{n,2}-a_{n+1,2})&cdots&2(a_{n,n}-a_{n+1,n})&sumlimits_{i=1}^n (a_{n,i}^2-a_{n+1,i}^2)end{bmatrix})

    然后用及不严谨的高斯消元解就彳亍

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,np;
    double c;
    struct matrix{
    	double bg[110];
    	double ele[110];
    }m[110];
    int main(){
    	cin>>n;
    	for(int i=1;i<=n+1;i++)
    		for(int o=1;o<=n;o++)
    			scanf("%lf",&m[i].bg[o]);
    	for(int i=1;i<=n;i++){
    		for(int o=1;o<=n;o++){
    			m[i].ele[o]=2*(m[i].bg[o]-m[i+1].bg[o]);
    			m[i].ele[n+1]+=m[i].bg[o]*m[i].bg[o]-m[i+1].bg[o]*m[i+1].bg[o];
    		}
    	}
    	for(int i=1;i<=n;i++){
    		np=i;
    		for(int o=i+1;o<=n;o++){
    			if(m[o].ele[i]>m[np].ele[i]){
    				np=i;
    			}
    		}
    		if(i!=np) swap(m[i],m[np]);
    		for(int o=1;o<=n;o++){
    			if(o!=i&&m[o].ele[i]){
    				c=m[o].ele[i]/m[i].ele[i];
    				for(int p=i;p<=n+1;p++){
    					m[o].ele[p]-=c*m[i].ele[p];
    				}
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		printf("%.3lf ",m[i].ele[n+1]/m[i].ele[i]);
    	}
    }
    
  • 相关阅读:
    java 开发面试题小整理(二)
    Java 字符串比较小知识
    适配器、工厂模式、线程池、线程组、互斥锁、Timer类、Runtime类、单例设计模式(二十四)
    多线程、死锁、线程安全、同步方法、代码块、休眠、守护线程、Thread、Runnable(二十三)
    RabbitMQ的几种典型使用场景
    SQL一些问题
    Redis和Memcached的区别
    Mongodb 使用场景和不使用场景
    Adapter as a WCF Binding
    ASP.NET MVC使用Filter解除Session, Cookie等依赖
  • 原文地址:https://www.cnblogs.com/zythonc/p/13412265.html
Copyright © 2011-2022 走看看