poj1830-高斯消元法利用(好)

本文介绍如何运用高斯消元法解决1830问题,通过构造特定矩阵并应用线性代数原理,探讨了该问题的所有可能解的数量。详细解释了如何建立矩阵模型以及实现算法的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先说下高斯消元:就是把增广矩阵化成上三角矩阵的过程,然后来判断解的情况。设A*X = B.A是一个n*m的矩阵,X是m*1的解矩阵,B是n*1的系数矩阵。 那么增广矩阵就是一个n*(m+1)的矩阵。

增广矩阵高斯消元后有3种情况:1. 某行前m个数全为0但是最后一个数不为0,这样导出矛盾,所以原方程无解。2. 当m == n且最后一行的第m个数不为0时有唯一解。3. 其他情况有无限多解,比如最后一行前m个数不止一个数不为0时。

    高斯消元算法的过程就是利用了矩阵的初等变换进行的,主要思想是要把对角元素化为1,然后通过从最下面往上一层层求解。


下面是1830怎么和高斯消元联系起来:

   对于每个灯有动它和不动它2种状态,用1,0表示,那么可以构造列向量X=[x1,x2....xn],Xi =0 或者1. 系数矩阵B[b1,b2...bn],变换矩阵A[n][n]; 假设 A*X = B,那么bi 等于 A的第i行元素和X对应相乘,那么我们可以这样来设置A[i][j]: 如果第j个灯操作会影响i,那么A[i][j]=1.

如果i的初始化状态和目标状态不同,那么b[i]=1. 因为b[i] 等于 A的第i行元素和X对应相乘。那么也就是说第i个灯最后的状态是不是会变是由X决定的,因为b[i] = sum(a[i][j] * X[j]),这里的求和视为模2运算也就是^,所以第i个灯最后的状态和初始比是不是变了是由每一个和i有关的灯决定的,这也就是为什么j会影响i设A[i][j] = 1的原因。也就是为什么要设b[i]是初始状态和最终状态的异或。。。。。。于是结果就变成了求方程A*X=B有多少个解。

#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include <algorithm>
#include<set>
#include<map>
#define LL long long
#define inf 0x7fffffff
#define linf 0x7fffffffffffffff
#define E 1e-9
#define M 100
#define N 32
using namespace std;
int n,k,m;
bool x[N];
bool ma[N][N];
int gauss()//n*(n+1)矩阵,化行阶梯形
{
    int i=0,j=0;
    for (; i<n,j<n;)
    {
        int k;
        for(k=i; k<n; k++)
            if(ma[k][j]!=0)
                break;
        if(k==n)
        {
            j++;
            continue;
        }
        if(i!=k)
        {
            for(int l=j; l<=n; l++) //交换
                swap(ma[i][l],ma[k][l]);
        }
        for(int r=i+1;r<n;r++)
        if(ma[r][j])
        {
            for(int l=j;l<=n;l++)
            ma[r][l]^=ma[i][l];//必须是异或
//            ma[r][l]-=ma[i][l];
        }
        i++,j++;
    }
    for(int r=i;r<n;r++)
    if(ma[r][n]!=0)
    return 0;//无解
    return (1<<(n-i));//因为解只能是0和1,所以最后剩了多少个变元,就有2的多少次方个解
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("ex.in","r",stdin);
#endif
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(ma,0,sizeof(ma));
        scanf("%d",&n);
        for (int i=0; i<n; ++i )
            scanf("%d",&x[i]);
        for (int i=0; i<n; ++i )
        {
            scanf("%d",&ma[i][n]);
            ma[i][n]^=x[i];
            ma[i][i]=1;
        }
        int a,b;
        while(scanf("%d%d",&a,&b)&&(a!=0||b!=0))
        {
            ma[b-1][a-1]=1;//方向
        }

        int num=gauss();
        if(num)
            printf("%d\n",num);
        else
            printf("Oh,it's impossible~!!\n");
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值