高斯消元
其实就™是加减消元法(模拟忒麻烦) 其实我觉得 学算法最主要是对算法的理解,因为裸题在正式赛里真的很少会出….都需要你对算法进行一番魔改♂ 如果你是死搬硬背的那肯定一脸懵逼
解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() {
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;
bz[f0]=
true;
l=f[f0][i];
for(
int j=
0; j<
3; j++)
if (f[j][i]) l=lcm(l,f[j][i]);
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;
}
}
for (
int j=
0; j<
3; j++) {
if (j!=f0) {
if (!f[j][i])
continue;
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
转载请注明原文地址: https://ju.6miu.com/read-1299029.html