hihocoder #1195 高斯消元一

hihocoder对算法解释得很详细,就复制粘贴来了

首先我们要计算出上三角矩阵,也就是将方程组变为:

a[1][1] * x[1] + a[1][2] * x[2] + ... + a[1][n] * x[n] = y‘[1]
      0 * x[1] + a[2][2] * x[2] + ... + a[2][n] * x[n] = y‘[2]
      0 * x[1] +       0 * x[2] + ... + a[3][n] * x[n] = y‘[3]
                                   ...
      0 * x[1] +       0 * x[2] + ... + a[n][n] * x[n] = y‘[n]
      0 * x[1] +       0 * x[2] + ... +       0 * x[n] = y‘[n + 1]
	                               ...
      0 * x[1] +       0 * x[2] + ... +       0 * x[n] = y‘[m]

也就是通过变换,将所有a[i][j](i>j)变换为0。同时要保证对角线上的元素a[i][i]不为0。

方法也很见简单,从第1行开始,我们利用当前行第i列不为0,就可以通过变换将i+1..M行第一列全部变换为0,接着对于第2行,我们用同样的方法将第3..M行第2列也变换为0...不断重复直到第n行为止。

假如计算到第i行时,第i列已经为0,则我们需要在第i+1..M行中找到一行第i列不为0的行k,并交换第i行和第k行,来保证a[i][i] != 0。但这时候还有可能出现一个情况,就是第i..M行中的i列均为0,此时可以判定,该方程组有多解。

当得到上三角矩阵后,就可以从第n行开始逆推,一步一步将a[i][j](i<j)也变换为0.

因为第n行为a[n][n] * x[n] = y‘[n],则x[n] = y‘[n] / a[n][n]。

第n-1行为a[n-1][n-1] * x[n - 1] + a[n][n] * x[n] = y‘[n - 1]。我们将得到的x[n]代入,即可计算出x[n-1]。

同样的依次类推就可以得到所有的x[1]..x[n]。

而对于多解和无解的判定:

当在求出的上三角矩阵中出现了 a[i][1] = a[i][2] = ... = a[i][n] = 0, 但是y‘[i] != 0时,产生了矛盾,即出现了无解的情况。

而多解的证明如下:

假设n=3,m=3,而我们计算出了上三角矩阵为:

a * x[1] + b * x[2] + c * x[3] = d
                      e * x[3] = f
                             0 = 0

当我们在第一个式子中消去x[3]后,有a * x[1] + b * x[2] = g,显然x[1]和x[2]有无穷多种可能的取值。

然后贴一发模板

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
#define db double
const int maxn=1008;
db a[maxn][maxn];
db x[maxn];
/*void Debug(int equ,int var)
{
    int i, j;
    for (i = 1; i <=equ; i++)
    {
        for (j = 1; j <= var + 1; j++)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}*/
int guess(int row,int col)
{
    int i,j,k;
    for(i=1;i<col;i++)
    {
        int r=i;
        for(j=row;j>i;j--)
        {
            if(fabs(a[j][i])>fabs(a[r][i]))
                r=j;
        }
        if(r==i&&fabs(a[i][i])<1e-7)    return -1;
        if(r!=i)    swap(a[r],a[i]);
        for(j=i+1;j<=row;j++)
        {
            for(k=col;k>i;k--)
                a[j][k]-=a[j][i]/a[i][i]*a[i][k];
            a[j][i]=0;
        }
    }
//    Debug(row,col);
    for(i=col-1;i<=row;i++)
    {
        for(j=1;j<col;j++)
            if(fabs(a[i][j])>1e-6)
                break;
        if(j==col&&fabs(a[i][col])>1e-6)
            return 0;
    }
    for(i=col-1;i>0;i--)
    {
        for(j=i+1;j<col;j++)
            a[i][col]-=a[i][j]*x[j];
        x[i]=a[i][col]/a[i][i];
    }
    return 1;
}
int main()
{
    int n,m,i,j;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)
        for(j=1;j<=n+1;j++)
            scanf("%lf",&a[i][j]);
    int ans=guess(m,n+1);
    if(ans==-1)    printf("Many solutions\n");
    else if(ans==0)    printf("No solutions\n");
    else
    {
        for(i=1;i<=n;i++)
            printf("%d\n",(int)(x[i]+0.5));
    }
    return 0;
}
时间: 2024-07-30 20:20:03

hihocoder #1195 高斯消元一的相关文章

hihoCoder 1196 高斯消元&#183;二

Description 一个黑白网格,点一次会改变这个以及与其连通的其他方格的颜色,求最少点击次数使得所有全部变成黑色. Sol 高斯消元解异或方程组. 先建立一个方程组. \(x_i\) 表示这个点是否被用过. 因为第二次使用同一个点,这个点的贡献就被消除了,所以每个点只会被用 0/1 次. \(a_{ij}\) 表示 \(j\) 点对 \(i\) 是否有影响,有影响为 1 否则为 0. 最后的一位表示最后的状态^最初的状态. 这样就列出来了 \(n*m\) 个方程组,一共 \(n*m\) 个

hihoCoder#1196 : 高斯消元&#183;二(开关灯问题)

传送门 高斯消元解异或方程组 小Ho在游戏板上忙碌了30分钟,任然没有办法完成,于是他只好求助于小Hi. 小Ho:小Hi,这次又该怎么办呢? 小Hi:让我们来分析一下吧. 首先对于每一个格子的状态,可能会对它造成影响的是其自身和周围4个格子,这五个格子被按下的总次数也就等于该格子所改变的总次数. 对于任意一个格子,如果这个格子改变了偶数次状态,则等价于没有发生改变. 我们可以将1看作格子亮着,0看作格子暗着,每改变1次就加1,最后格子的状态等于其总数值 MOD 2. 则其运算结果刚好满足异或运算

HiHoCoder [Offer收割]编程练习赛6 C. 图像算子(高斯消元小数版)

传送门 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在图像处理的技术中,经常会用到算子与图像进行卷积运算,从而达到平滑图像或是查找边界的效 果. 假设原图为 H×W 的矩阵 A,算子矩阵为 D×D 的矩阵 Op ,则处理后的矩阵 B 大小为 (H?D+1)×(W?D+1).其中: B[i][j]=∑(A[i?1+dx][j?1+dy]?Op[dx][dy])|(dx=1..D,dy=1..D),1≤i≤H?D+1,1≤j≤W?D+1 给定矩阵 A 和 B ,以及

poj_1222_高斯消元

第一次学习使用高斯消元,将灯板化为线性方程组,进行求解. /*######################################################################### # File Name: poj_1222.cpp # Author: CaoLei # Created Time: 2015/7/20 15:48:04 ###################################################################

HDU 4870 Rating(高斯消元)

HDU 4870 Rating 题目链接 题意:一个人注册两个账号,初始rating都是0,他每次拿低分的那个号去打比赛,赢了加50分,输了扣100分,胜率为p,他会打到直到一个号有1000分为止,问比赛场次的期望 思路:f(i, j)表示i >= j,第一个号i分,第二个号j分时候,达到目标的期望,那么可以列出转移为f(i, j) = p f(i', j') + (1 - p) f(i'' + j'') + 1 f(i', j')对应的是赢了加分的状态,f(i'', j'')对应输的扣分的状态

【BZOJ 4171】 4171: Rhl的游戏 (高斯消元)

4171: Rhl的游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 74  Solved: 33[Submit][Status][Discuss] Description RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色 .每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子 ),黑变白,白变黑.RHL希望把所有格子都变成白色的.不幸

POJ 1830 开关问题 高斯消元,自由变量个数

http://poj.org/problem?id=1830 如果开关s1操作一次,则会有s1(记住自己也会变).和s1连接的开关都会做一次操作. 那么设矩阵a[i][j]表示按下了开关j,开关i会被操作一次,记得a[i][i] = 1是必须的,因为开关i操作一次,本身肯定会变化一次. 所以有n个开关,就有n条方程, 每个开关的操作次数总和是:a[i][1] + a[i][2] + ... + a[i][n] 那么sum % 2就代表它的状态,需要和(en[i] - be[i] + 2) % 2

BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]

以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高斯消元判断是否和已选择的线性相关 每一位记录pivot[i]为i用到的行 枚举要加入的数字的每一个二进制为1的位,如果有pivot[i]那么就异或一下(消元),否则pivot[i]=这个数并退出 如果最后异或成0了就说明线性相关... #include <iostream> #include &l

[bzoj1013][JSOI2008]球形空间产生器sphere-题解[高斯消元]

Description 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体.现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器. Input 第一行是一个整数n(1<=N=10).接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标.每一个实数精确到小数点后6位,且其绝对值都不超过20000. Output 有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开.每个实数精确到