高斯消元模板&高斯消元·一 HihoCoder1195

高斯消元模板&高斯消元·一 HihoCoder1195

Part 0

这道题就是高斯消元的板子题。

高斯消元,就是用来解一个多项式方程的算法。当然还能判断这个方程是有多组解还是无解。下面来稍微解释一下它的原理。

Part 1

首先先想一想我们是怎么解多元一次方程组的,从中有没有什么通用解法。高斯消元其实就是这样一个通用解法。

有那么多个未知数,我们可以一个一个进行消去。

假设初始有m个n元方程(a数组为系数,x数组为未知数)

a [ 1 ] [ 1 ] ∗ x [ 1 ] + a [ 1 ] [ 2 ] ∗ x [ 3 ] + ⋅ ⋅ ⋅ + a [ 1 ] [ n ] ∗ x [ n ] = b [ 1 ] a[1][1]*x[1]+a[1][2]*x[3]+ \cdot \cdot \cdot +a[1][n]*x[n]=b[1] a[1][1]x[1]+a[1][2]x[3]++a[1][n]x[n]=b[1]

a [ 2 ] [ 1 ] ∗ x [ 1 ] + a [ 2 ] [ 2 ] ∗ x [ 3 ] + ⋅ ⋅ ⋅ + a [ 2 ] [ n ] ∗ x [ n ] = b [ 2 ] a[2][1]*x[1]+a[2][2]*x[3]+ \cdot \cdot \cdot +a[2][n]*x[n]=b[2] a[2][1]x[1]+a[2][2]x[3]++a[2][n]x[n]=b[2]

⋅ ⋅ ⋅ \cdot \cdot \cdot

a [ m ] [ 1 ] ∗ x [ 1 ] + a [ m ] [ 2 ] ∗ x [ 3 ] + ⋅ ⋅ ⋅ + a [ m ] [ n ] ∗ x [ n ] = b [ m ] a[m][1]*x[1]+a[m][2]*x[3]+ \cdot \cdot \cdot +a[m][n]*x[n]=b[m] a[m][1]x[1]+a[m][2]x[3]++a[m][n]x[n]=b[m]

那么我们对于第二行以下的所有方程都消去x[1]这个未知数,就拿第m条方程为例,其消去x[1]这个未知数就是这样。

0 ∗ x [ 1 ] + ( a [ m ] [ 2 ] − a [ m ] [ 1 ] / a [ 1 ] [ 1 ] ∗ a [ 1 ] [ 2 ] ) ∗ x [ 3 ] + ⋅ ⋅ ⋅ + ( a [ m ] [ n ] − a [ m ] [ 1 ] / a [ 1 ] [ 1 ] ∗ a [ 1 ] [ n ] ) ∗ x [ n ] = b [ m ] − b [ 1 ] ∗ ( a [ m ] [ 1 ] / a [ 1 ] [ 1 ] ) 0*x[1]+(a[m][2]-a[m][1]/a[1][1]*a[1][2])*x[3]+ \cdot \cdot \cdot +(a[m][n]-a[m][1]/a[1][1]*a[1][n])*x[n]=b[m]-b[1]*(a[m][1]/a[1][1]) 0x[1]+(a[m][2]a[m][1]/a[1][1]a[1][2])x[3]++(a[m][n]a[m][1]/a[1][1]a[1][n])x[n]=b[m]b[1](a[m][1]/a[1][1])

以此操作n-1次,一次次消去未知数,然后就可以的出x[n]的值,然后代入上一条方程就会得出x[n-1]的值,然后就可以的出所有未知数的值。

对于无解与多解的判定就直接扔在代码里了。

高斯消元的模板就是那个结构体里的东西。

代码及解释如下

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define eps 1e-6
#define M 505
using namespace std;
struct Matrix{
	double num[M<<1][M<<1];
	double Ans[M<<1];
	double val[M<<1];
	int n,m;//m行n列 
	void resize(int x,int y){n=x,m=y;}
	void Read(){
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++)scanf("%lf",&num[i][j]);
			scanf("%lf",&Ans[i]);
		}
	}
	void swap_line(int x,int y){
		if(x==y)return;
		for(int i=1;i<=n;i++)swap(num[x][i],num[y][i]);
		swap(Ans[x],Ans[y]);
	}
	void Print(){
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++)printf("%.2lf ",num[i][j]);
			printf("%.2lf\n",Ans[i]);
		}
	}
	void solve(){
		memset(val,0,sizeof(val));
		bool Many_ans=false;//是否有多组解 
		for(int step=1;step<=n;step++){//当前在处理哪一个物品(也就是消去哪个元) 
			bool flag=false;
			for(int i=step;i<=m;i++){
				if(fabs(num[i][step])>eps){
					flag=true;
					swap_line(step,i);
					break;
				}
			}
			//如果剩下的每一个方程的这个元的系数都为0,那么这个元的取值是随意的,那么就有多组解 
			if(!flag){
				Many_ans=true;
				continue;
			}
			for(int i=step+1;i<=m;i++){//将下面的方程进行消元 
				for(int j=step+1;j<=n;j++)num[i][j]-=num[step][j]*(num[i][step]/num[step][step]);
				Ans[i]-=Ans[step]*(num[i][step]/num[step][step]);
				num[i][step]=0;
			}
		}
		for(int i=1;i<=m;i++){//先判断无解,在判断多解 
			bool flag=false;
			for(int j=i;j<=n;j++)if(fabs(num[i][j])>eps){flag=true;break;}
			if(!flag&&fabs(Ans[i])>eps){//如果有一个方程它的所有未知数的系数都为0但是它们的和却不为0 
				puts("No solutions");
				return;
			}
		}
		if(Many_ans){
			puts("Many solutions");
			return;
		}
		for(int i=n;i>=1;i--){
			for(int j=i+1;j<=n;j++)Ans[i]-=num[i][j]*val[j];//将本方程的所有未知数都带入数值并消去 
			val[i]=Ans[i]/num[i][i];//解出当前行的方程的未知数 
		}
		//输出为本题的特殊要求 
		for(int i=1;i<=n;i++)printf("%d\n",(int)(0.5+val[i]));//四舍五入 
	}
}A;
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	A.resize(n,m);
	A.Read();
	A.solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值