高斯消元模板

#include <iostream>
#include <cstdio>
#include <cstring>
/*
高斯消元就是模拟矩阵的线性变换,把矩阵化成上三角 然后判断解的情况.
*/
typedef __int64 ll;
using namespace std;
const int maxn = 105;
ll a[maxn][maxn],x[maxn];//增广矩阵
int row,col;//线性方程组的方程数为row 变元数为col 则增广矩阵的行数为 row(0-(row-1)) col(0-col)
bool free_x[maxn];
ll gcd(ll x,ll y)
{
    if(!y) return x;
    return gcd(y,x%y);
}
ll lcm(ll x,ll y)
{
    return x/gcd(x,y)*y;
}
void Debug()
{
    for(int i=0;i<row;i++)
    {
        for(int j=0;j<col+1;j++)
            printf("%I64d ",a[i][j]);
        printf("\n");
    }
    printf("\n");
}
void swaprowxy(int x,int y)//交换x y两行
{
    for(int i=0;i<col+1;i++)
    {
        int tp=a[x][i];
        a[x][i]=a[y][i];
        a[y][i]=tp;
    }
}
void swapcolxy(int x,int y)//交换x y两列
{
    for(int i=0;i<row;i++)
    {
        int tp=a[i][x];
        a[i][x]=a[i][y];
        a[i][y]=tp;
    }
}
ll Abs(ll x)
{
    if(x<0) return -x;
    return x;
}
int Gauss()
{
    int r,c;
    for(r=0,c=0;r<row&&c<col;r++,c++) //用第r行消掉其余((r+1)-(row-1))行的第c列
    {
        int maxr=r;//首先找到 (r-(row-1))行中第c列绝对值最大的行 与第r行交换(防止除法误差什么的?)
        for(int i=r+1;i<row;i++)
            if(Abs(a[i][c])>Abs(a[maxr][c])) maxr=i;
        if(maxr!=r)
            swaprowxy(maxr,r);
        //当把第r行换成Abs(a[r][c])最大的时候仍然出现 a[r][c]==0 则说明以下的所有行的第c列都为0 则直接处理第r行的第c+1列
        if(a[r][c]==0)
        {
            r--;
            continue;
        }
        for(int i=r+1;i<row;i++)//枚举以下的所有行 利用第r行消除掉以下所有行的第c列
        {
            ll lc=lcm(Abs(a[r][c]),Abs(a[i][c]));
            ll t1=lc/a[r][c],t2=lc/a[i][c];
            int sign=1;
            if((a[r][c]<0&&a[i][c]>0)||(a[r][c]>0&&a[i][c]<0))
                sign=-1;
            for(int j=c;j<col+1;j++)
            {
                if(!a[i][j]) continue;
                a[i][j]=a[i][j]*t2-sign*a[r][j]*t1;
            }
        }
    }
    Debug();
    //1.return -1; 这种情况下是无解的 说明增广矩阵中存在着(0,0....,a)这样的行(a!=0)
    for(int i=r;i<row;i++)
        if(a[i][c]!=0) return -1;
    //2.return -2; 这种情况下有无穷解 在增广矩阵中出现(0,0...,0)这样的行 没有形成严格的上三角
    //出现的行数就等于自由变元的个数
    if(r<col)
    {
        for(int i=r-1;i>=0;i--)
        {
            int free_num=0,free_index;//变元的数量和变元的下标
            for(int j=0;j<col;j++)
            {
                if(a[i][j]!=0&&!free_x[j]) free_num++,free_index=j;
            }
            if(free_num>1) continue;//未确定的变元数量大于1
            //这个方程中只有一个x是未知的
            int temp=a[i][col];//第i个方程的常数
            for(int j=0;j<col;j++)
            {
                if(a[i][j]!=0&&j!=free_index) temp-=a[i][j]*x[j];
            }
            x[free_index]=temp/a[i][free_index];
            free_x[free_index]=1;//这个x的值是确定的
        }
        return col-r;
    }
    for(int i=col-1;i>=0;i--)
    {
        int temp=a[i][col];
        for(int j=i+1;j<col;j++)
        {
            if(a[i][j]!=0) temp-=a[i][j]*x[j];
        }
        if(temp%a[i][i]!=0) return -2;//浮点数解 没有整数解.
        x[i]=temp/a[i][i];
    }
    return 0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&row,&col))
    {
        memset(a,0,sizeof(a));
        memset(free_x,0,sizeof(free_x)); //初始所有的元都是不确定的
        memset(x,0,sizeof(x));//记录xi的值
        for(int i=0;i<row;i++)
            for(int j=0;j<col+1;j++)
                scanf("%I64d",&a[i][j]);
        Debug();
        int ans_num=Gauss(); //返回解的个数
        printf("%d\n",ans_num);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值