hihor学习日记:hiho一下 第五十六周(高斯消元)

http://hihocoder.com/contest/hiho56/problem/1

高斯消元就是用多元一次方程求解
小Ho:<吧唧><吧唧><吧唧>

小Hi:小Ho,你还吃呢。想好了么?

小Ho:肿抢着呢(正想着呢)…<吞咽>…我记得这个问题上课有提到过,应该是一元一次方程组吧。

我们把每一件商品的价格看作是x[1]…x[n],第i个组合中第j件商品数量记为a[i][j],其价格记作y[i],则可以列出方程式:
在这里插入图片描述
我们可以对方程组进行3种操作而不改变方程组的解集:

  1. 交换两行。

  2. 把第i行乘以一个非0系数k。即对于j = 1…n, 令a[i][j] = ka[i][j], y[i]=ky[i]

  3. 把第p行乘以一个非0系数k之后加在第i行上。即对于j=1…n, 令a[i][j] = a[i][j]+ka[p][j],y[i]=y[i]+kp[i]

以上三个操作叫做初等行变换。

我们可以使用它们,对这个方程组中的a[i][j]进行加减乘除变换,举个例子:在这里插入图片描述
我们可以通过 式子(1) - 式子(2) * (a[1][1] / a[2][1]),将第1行第1列的a[1][1]变换为0。

对整个方程组进行多次变换之后,可以使得a[i][j]满足:在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

伪代码:

// 处理出上三角矩阵
For i = 1..N
    Flag ← False
    For j = i..M                // 从第i行开始,找到第i列不等于0的行j
        If a[j][i] != 0 Then
            Swap(j, i)          // 交换第i行和第j行
            Flag ← True
            Break
        End If
    End For
    // 若无法找到,则存在多个解
    If (not Flag) Then
        manySolutionsFlag ← True // 出现了秩小于N的情况
        continue;
    End If
    // 消除第i+1行到第M行的第i列
    For j = i+1 .. M
        a[j][] ← a[j][] - a[i][] * (a[j][i] / a[i][i])
        b[j] ← b[j] - b[i] * (a[j][i] / a[i][i])
    End For
End For 

// 检查是否无解,即存在 0 = x 的情况
For i = 1..M
    If (第i行系数均为0 and (b[i] != 0)) Then
        return "No solutions"
    End If
End For

// 判定多解
If (manySolutionsFlag) Then
	return "Many solutions"
End If

// 此时存在唯一解
// 由于每一行都比前一行少一个系数,所以在M行中只有前N行有系数
// 解析来从第N行开始处理每一行的解
For i = N .. 1
    // 利用已经计算出的结果,将第i行中第i+1列至第N列的系数消除
    For j = i + 1 .. N
        b[i] ← b[i] - a[i][j] * value[j]
        a[i][j]0
    End For
    value[i] ← b[i] / a[i][i]
End For

AC代码:

注意,用double的大于0的时候,要去一个eps近似值,
还有最后输出的时候要转成int(x+0.5),原因我还不知道,如果有知道的,可以在评论区指出来,感谢^- ^

#include <bits/stdc++.h>

using namespace std;
#define LL long long
const int Mod = 1e9 + 7;
const int maxn = 1e3 + 5;
const double eps = 0.0000001;
const int INF = 0x3f3f3f3f;

int n, m;
double a[maxn][maxn], x[maxn];
bool manySolutionFlag = false, noSolution = false;

void Swap(int i, int j) {
    for (int k = 1; k <= n + 1; k ++)
        swap(a[i][k], a[j][k]);
}

bool Check(int i) {
    bool vis = false;
    for (int j = 1; j <= n; j ++) {
        if(fabs(a[i][j]) >= eps) vis = true;
    }
    if(!vis && fabs(a[i][n + 1]) >= eps) return false;
    return true;
}

void GS() {
    for (int i = 1; i <= n; i ++) {
        bool flag = false;
        for (int j = i; j <= m; j ++) {
            if(a[j][i] != 0) {
                Swap(j, i);
                flag = true;
                break;
            }
        }
        if(!flag) {
            manySolutionFlag = true;
        }
        for (int j = i + 1; j <= m; j ++)
            for (int k = n + 1; k >= i; k --)
                a[j][k] = a[j][k] * 1. - a[i][k] * (a[j][i] * 1./a[i][i] * 1.) * 1.;

    }
    for (int i = 1; i <= m; i ++) {
        if(!Check(i)) {
            noSolution = true;
            return ;
        }
    }
    for (int i = n; i >= 1; i --) {
        for (int j = i + 1; j <= n; j ++) {
            a[i][n + 1] = a[i][n + 1] - a[i][j] * x[j];
            a[i][j] = 0;
        }
        x[i] = a[i][n + 1] * 1./a[i][i] * 1.;
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i ++)
        for (int j = 1; j <= n + 1; j ++)
            cin >> a[i][j];
    GS();
    if(noSolution) cout << "No solutions" << endl;
    else if(manySolutionFlag) cout << "Many solutions" << endl;
    else {
        for (int i = 1; i <= n; i ++)
            cout << (int)(x[i] +0.5) << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/85213673
今日推荐