高斯消元

本文介绍了一个使用高斯消元法求解线性方程组的C++程序实现。该程序能够处理方程组并判断其是否有解、唯一解或多解的情况,并能求出解或最小化解的数量。适用于解决诸如网格中黑白格子最少数量等实际问题。
#include<cstdio>
#include<cstring>
#include<ctime>
#include<map>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=300;
const int inf=0x3f3f3f3f;
int equ,var;//equ是方程数也就是行数,var是变元也就是列数
int a[maxn][maxn];//增广矩阵
int x[maxn];//解集
int free_x[maxn];//自由变元(多解枚举自由变元可以使用)
int free_num;//自由变元的个数
//返回值为-1代表无解,0为唯一解,否则返回自由变元的个数
int Gauss()
{
    int max_r,col,k;
    free_num=0;
    for(k=0,col=0; k<equ&&col<var; k++,col++)
    {
        //col代表正在处理的这一列
        max_r=k;//表示当前列中元素绝对值最大的行
        for(int i=k+1; i<equ; i++)
        {
            if(abs(a[i][col])>abs(a[max_r][col]))
                max_r=i;
        }
        if(max_r!=k)//与第k行交换
        {
            for(int j=col; j<var+1; j++)
                swap(a[k][j],a[max_r][j]);
        }
        if(a[k][col]==0)//说明该col列第k行一下全是0,处理当前行的下一列
        {
            k--;
            free_x[free_num++]=col;
            continue;
        }
        for(int i=k+1; i<equ; i++) //枚举要删除的行
        {
            if(a[i][col]!=0)
            {
//                int LCM=lcm(abs(a[i][col],abs(a[k][col])));
//                int ta=LCM/abs(a[i][col]);
//                int tb=LCM/abs(a[k][col]);
//                if(a[i][col]*a[k][col]<0)
//                    tb=-tb;
//                for(int j=col;j<var+1;j++)
//                {
//                    a[i][j]=a[i][j]*ta-a[k][j]*tb;
//                }
                for(int j=col; j<var+1; j++)
                {
                    a[i][j]^=a[k][j];
                }
            }
        }
    }
    for(int i=k; i<equ; i++)
        if(a[i][col]!=0)
            return -1;//无解
    if(k<var)//有多解
    {
        int star=1<<(var-k);//枚举变元
        int res=inf;
        for(int i=0;i<star;i++)
        {
            int cnt=0;
            int tmp=i;
            for(int j=0;j<var-k;j++)//得到每一个变元的值
            {
                x[free_x[j]]=(tmp&1);
                cnt+=x[free_x[j]];
                tmp>>=1;
            }
            for(int j=k-1;j>=0;j--)//回代
            {
                int tmp=a[j][var];
                for(int l=j+1;l<var;l++)
                    tmp^=(a[j][l]&&x[l]);
                x[j]=tmp;
                cnt+=x[j];
            }
            res=min(res,cnt);//选取最小值
        }
        return res;
    }
    //唯一解 ,回代
    for(int i=var-1; i>=0; i--)
    {
        x[i]=a[i][var];
        for(int j=i+1; j<var; j++)
            x[i]^=(a[i][j]&&x[j]);
    }
    return 0;
}
void init(int n)
{
    memset(a,0,sizeof(a));
    memset(x,0,sizeof(x));
    memset(free_x,1,sizeof(free_x));
    equ=n*n;
    var=n*n;
    for(int i=0; i<n; i++)//建立方程组
        for(int j=0; j<n; j++)
        {
            int t=i*n+j;
            a[t][t]=1;//自己的变元肯定对自己有影响
            if(i>0) a[(i-1)*n+j][t]=1;
            if(j>0) a[t-1][t]=1;
            if(i<n-1) a[(i+1)*n+j][t]=1;
            if(j<n-1) a[t+1][t]=1;
        }
}
int main()
{
    int ncase,Z=0;
    scanf("%d",&ncase);
    while(ncase--)
    {
        int n;
        scanf("%d",&n);
        init(n);
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<n; j++)
            {
                char c;
                scanf(" %c",&c);
                if(c=='w')
                    a[i*n+j][n*n]=1;
                else a[i*n+j][n*n]=0;
            }
        }
        int tmp=Gauss();
        if(tmp==-1)
            printf("inf\n");
        else
            printf("%d\n",tmp);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值