高斯消元初步

高斯消元

其实就™是加减消元法(模拟忒麻烦)
其实我觉得 学算法最主要是对算法的理解,因为裸题在正式赛里真的很少会出….都需要你对算法进行一番魔改♂ 如果你是死搬硬背的那肯定一脸懵逼

解N元一次方程组

就和加减消元一毛一样,大概分以下几个步骤
用一个数组存下未知数的系数

1.枚举所有未知数,一个个消掉:
2.找一个系数非0的,作减数
3.算一下所有系数的最小公因数,然后把每个系数(其他项也要)乘到最小公因数
4.然后把所有式子都减去那个作减数的式子,并将那个式子标记一下,下次不能再做减数
(因为其实已经被化简掉了,如果再用来当减数那就和用一个式子化简出两个未知数带进去的后果一样)

5.到最后每一个式子肯定都被化简成了未知数=a的这种形式,求一遍答案就可以了.

如果未知数比较少,比如才三个的话(推了20分钟还少握草)就可以考虑手推公式,这样效率高而且代码短

例题

Description
现在有 a,b,c 三种物品,如果他们安 x:y:z 混合,就能产生一种神奇的物品 D 。
当然不一定只产生一份 D ,但 a,b,c 的最简比一定是 x:y:z
现在给你 3 种可供选择的物品 A,B,C :
A,B,C 都是由 a,b,c 以一定比例组合成的 , 求出最少的物品数 , 使得他们能凑出整数个 D
物品(这里的最少是指三者个数的总和最少)
Input
第一行三个整数,表示 d 的配比( x,y,z )
接下来三行,表示 A,B,C 的配比,每行三个整数( <=10000 ) 。
Output
四个整数,分别表示在 A+B+C 最 小 的前提下 A,B,C ,D 的个数
目标答案 <=10000
如果不存在满足条件的方案,输出 NONE
Sample Input
3 4 5
1 2 3
3 7 1
2 1 2
Sample Output
8 1 5 7
Data Constraint
Hint
50% 的数据保证答案中任意一个数 <=100
100% 的数据保证答案中任意一个数 <=10000

DEMO

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
ll cpy[3][4],f[3][4]; //[第几条式子][第几个元]
ll ans[4];
bool bz[4];
bool isInt;
int gcd(ll a,ll b){
    return (b==0)?a:gcd(b,a%b);
}
int abs(int x) {
    return (x>0)?x:-x;
}
int lcm(ll a,ll b) {
    return (a*b/gcd(a,b));
}
void defact() { //这名字是我乱取的233
    memset(bz,0,sizeof bz);
    ll f0,l,divi; 
    for (int i=1; i<4; i++) { //第几个元
        f0=0;
        while (f[f0][i]==0 || bz[f0])  f0=f0%3+1; //找第一个系数非0的
        bz[f0]=true;
        l=f[f0][i];
        for(int j=0; j<3; j++) 
            if (f[j][i]) l=lcm(l,f[j][i]); //求所有系数的lcm
        for(int j=0; j<3; j++)  {
            if (!f[j][i]) continue; 
            divi = l/f[j][i];
            for (int k=0; k<4; k++) {
                f[j][k]*=divi; //把整个式子全部乘上lcm/f[j][i]
            }
        }

        for (int j=0; j<3; j++) {
            if (j!=f0) {
                if (!f[j][i]) continue; //如果系数已经是0了那就不用管
                for (int k=0;k<4; k++) {
                    f[j][k]-=f[f0][k]; //消元
                }
            }
        }
    }
    for(int i=0; i<3; i++)  //找答案
        for(int j=1; j<4; j++) {
            if (f[i][j]!=0) {
                if (f[i][0]%f[i][j]) isInt=false;
                ans[j]=f[i][0]/f[i][j];
                break;
            }
        }
}
int main(){
    for (int i=0; i<3; i++) {
        scanf("%d",&f[i][0]);
    }
    for (int i=0; i<3; i++) {
        scanf("%d %d %d",&f[0][i+1],&f[1][i+1],&f[2][i+1]);
    }
    memcpy(cpy,f,sizeof f);
    for (int d=1; d<=10000; d++) {
        memcpy(f,cpy,sizeof cpy);
        for (int i=0; i<3; i++) {
            f[i][0]=f[i][0]*d;
        }
        isInt=true;
        defact();
        if (isInt && ans[1]>=0 && ans[2]>=0 && ans[3]>=0) {
            cout<<ans[1]<<" "<<ans[2]<<" "<<ans[3]<<" "<<d<<endl;
            return 0;
        }
    }
    cout<<"NONE"<<endl;
}

进阶

自由元

自由元X的意义是,其取值不唯一。每当他取一个确定的值,方程就有一组新的解。
因此如果有x个自由元,那么整组方程的解的个数也就是 Tx
如何判断: 高斯消元消某个变量x时发现以下所有方程当前此位系数都是0,则此变量是一个自由元。

对于一组方程,自由元并不是固定的,但自由元的个数是固定的。
比如说a+b=常数,当a确定时b确定,反过来当b确定时a也确定,所以可以分别说a是自由元或b是自由元,但不能说a,b都是自由元。 个数总是1.

异或方程组

异或的逆运算是他本身,其余同普通方程组。
axorbxorb=a
例题:jzoj1321

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值