【本校OJ】P4927 高斯消元法

标题党,高斯消元法大概就是线代课学的各种初等行变换,我暂且蒙在鼓里,,,

思路:

找出每个灯和开关之间的关系,列出方程组求解。——HINT

以每个开关的状态为未知数列出三十元一次方程组。在其增广矩阵中,矩阵的行与灯一一对应,列与开关一一对应,对于每个开关Y,若Y可控制第X个灯,则X行Y列元素为1,否则为0;每行最后一列(0或1)表示对应灯的初始状态。

例:

对灯阵的初始状态:
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
可列出增广矩阵:
1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0

然后对该方程组对应的增广矩阵进行异或行变换
异或行变换
与解一般的线性方程组一样,目的是将矩阵化为简化阶梯形,而本题中需要对每行进行异或操作。即当简化至第x行时,
对换变换:若第x行第x列元素为0,则向下寻找第x列元素为1的行与原第x行进行对换。
异或变换:至第x行x列元素为1时,从第1行开始,若非x行的第x列元素为1,则该行每个元素对第x行对应元素取异或,否则不操作。如此可保证矩阵中除最后一列外只有第x行第x列的元素为1,即形成简化阶梯形。

步骤:
1.输入5x6的矩阵(input);
2.将其转化为30x31的增广矩阵(equation);
3.行变换(rowoperate);
4.以矩阵形式输出30x31矩阵的最后一列(output);

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const int n = 30;
const int k = 5;
void input(int [][k + 1]);
void equation(int [][k + 1], int [][n + 1]);
void rowoperate(int , int [][n + 1]);
void ans(int [][n + 1]);

int main(){
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int m;
    int arr[k][k + 1], arr2[n][n + 1];
    scanf("%d", &m);
    for (int t = 1; t <= m; t++)
    {
        input(arr);
        memset(arr2, 0, sizeof(int) * n * (n + 1));
        equation(arr, arr2);
        printf("PUZZLE #%d\n", t);
        for (int i = 0; i < n; i++)
            rowoperate(i, arr2);
        ans(arr2);
    }
    return 0;
}

void input(int arr[][k + 1])
{
    for (int x = 0; x < k; x++)
        for (int y = 0; y <= k; y++)
            scanf("%d", &arr[x][y]);
}

void equation(int arr[][k + 1], int arr2[][n + 1])
{
    for (int x = 0; x < k; x++)
        for (int y = 0; y <= k; y++)
        {
            int pos = x * (k + 1) + y;
            arr2[pos][n] = arr[x][y];
            arr2[pos][pos] = 1;
            if (x > 0)
                arr2[pos][pos - (k + 1)] = 1;
            if (x < k - 1)
                arr2[pos][pos + (k + 1)] = 1;
            if (y > 0)
                arr2[pos][pos - 1] = 1;
            if (y < k)
                arr2[pos][pos + 1] = 1;
        }
}

void rowoperate(int i, int arr2[][n + 1])
{
    if (arr2[i][i] == 0)
    {
        int j = i + 1, temp;
        while (arr2[j][i] == 0)
            j++;
        for (int y = 0; y <= n; y++)
        {
            temp = arr2[j][y];
            arr2[j][y] = arr2[i][y];
            arr2[i][y] = temp;
        }
    }
    for (int x = 0; x < n; x++)
    {
        if (x == i)
            continue;
        if (arr2[x][i] == 1)
            for (int y = 0; y <= n; y++)
            {
                arr2[x][y] ^= arr2[i][y];
            }
    }
}

void ans(int arr2[][n + 1])
{
    for (int x = 0; x < n; x++)
    {
        printf("%d", arr2[x][n]);
        x % 6 == 5 ? puts("") : putchar(' ');
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值