具体原理线代有学,百度一下一大把,这里整理一下模板
高斯-约旦消元待补
整数类型高斯消元
可以解同余方程组的
eg:
k1 * x1 + k2 * x2 + …… + kn * xn = Y - X + 1(mod 7)。
有m个这样的方程
//可以解同余方程组
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#define nmax 510
using namespace std;
int a[nmax][nmax];
int x[nmax];
int free_x[nmax],mod=7;
int gcd(int a,int b){
if(!b) return a; else return gcd(b,a%b);
}
long long inv(long long a,long long m){
if(a == 1)return 1;
return inv(m%a,m)*(m-m/a)%m;
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
//-2表示有浮点数解,但无整数解,-1表示无解.0表示唯一解,大于0表示无穷解,并返回自由变元的个数
//有equ个方程,var个变元,增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var.
int Gauss(int equ,int var){
//max_r当前这列绝对值最大的行.col:当前处理的列.
int k,max_r,col = 0,ta,tb;
int LCM,temp,num = 0,free_index;
for(int i=0;i<=var;i++){
x[i]=0;
free_x[i]=true;
}
for(k = 0;k < equ && col < var;k++,col++){
// 枚举当前处理的行.
// 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)
max_r=k;
for(int i=k+1;i<equ;i++){
if(abs(a[i][col])>abs(a[max_r][col]))
max_r=i;
}
if(max_r!=k){// 与第k行交换.
for(int j=k;j<var+1;j++)
swap(a[k][j],a[max_r][j]);
}
if(a[k][col]==0){// 说明该col列第k行以下全是0了,则处理当前行的下一列.
free_x[num++] = col;
k--;
continue;
}
for(int i=k+1;i<equ;i++){// 枚举要删去的行.
if(a[i][col]!=0){
LCM = lcm(abs(a[i][col]),abs(a[k][col]));
ta = LCM/abs(a[i][col]);
tb = LCM/abs(a[k][col]);
if(a[i][col]*a[k][col]<0)tb=-tb;//异号的情况是相加
for(int j=col;j<var+1;j++){
a[i][j] = ((a[i][j]*ta-a[k][j]*tb)%mod+mod)%mod;
}
}
}
}
// 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
for (int i = k; i < equ; i++){
if (a[i][col] != 0) return -1;
}
// 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
// 且出现的行数即为自由变元的个数.
if (k < var){
return var - k; // 自由变元有var - k个.
}
//3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.
// 计算出Xn-1, Xn-2 ... X0
for (int i = var - 1; i >= 0; i--){
temp = a[i][var];
for (int j = i + 1; j < var; j++){
if (a[i][j] != 0)
temp =((temp- a[i][j] * x[j])%mod+mod)%mod;
}
//if (temp % a[i][i] != 0) return -2; // 说明有浮点数解,但无整数解.
while (temp % a[i][i] != 0) //本题的变化,其实直接不加这句也对
temp+=mod; // 说明有浮点数解,但无整数解.
x[i] = (temp*inv(a[i][i],mod))%mod;
}
return 0;
}
void init()
{
memset(a, 0, sizeof(a));
memset(x, 0, sizeof(x));
}
map<string,int> mp;
int main()
{
mp["MON"]=1;
mp["TUE"]=2;
mp["WED"]=3;
mp["THU"]=4;
mp["FRI"]=5;
mp["SAT"]=6;
mp["SUN"]=7;
int n,m;
while(scanf("%d%d",&n,&m)!=-1)
{
if(n==0&&m==0) break;
init();
char s1[15],s2[15];
for(int i=0;i<m;i++)
{
int k;
scanf("%d %s %s",&k,s1,s2);
a[i][n]=((mp[s2]-mp[s1]+1)%mod+mod)%mod;
int t;
while(k--)
{
scanf("%d",&t);
t--;
a[i][t]++;
a[i][t]%=mod;
}
}
int flag = Gauss(m,n);
if(flag == -1)
printf("Inconsistent data.\n");
else if(flag > 0)
printf("Multiple solutions.\n");
else
{
for(int i = 0; i < n; i++)
if(x[i] <= 2)
x[i] += 7;///根据题意要求天数必须在3~9之间
for(int i = 0; i < n-1; i++)
printf("%d ",x[i]);
printf("%d\n",x[n-1]);
}
}
return 0;
}
浮点类型
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 1010;
const double EPS=1e-7;
int m,n;
double a[N][N],x[N];
int Gauss(int m,int n){
int col=0, k=0;//col为列号,k为行号
for (;k<m&&col<n;++k,++col){
int r = k;
for (int i=k+1;i<m;++i)
if(fabs(a[i][col])>fabs(a[r][col]))r=i;
if (fabs(a[r][col])<EPS){k--;continue;}//列全为0
if (r!=k)for(int i=col;i<=n;++i)
swap(a[k][i],a[r][i]);
for (int i=k+1;i<m;++i)//消元
if(fabs(a[i][col])>EPS){
double t = a[i][col]/a[k][col];
for (int j=col;j<=n;j++)a[i][j]-=a[k][j]*t;
a[i][col] = 0;
}
}
for(int i=k ;i<m ;++i)//无解
if (fabs(a[i][n])>EPS) return -1;
if (k < n) return n - k; //自由元个数
for (int i =n-1; i>=0; i--){//回带求解
double temp = a[i][n];
for (int j=i+1; j<n; ++j)
temp -= x[j] * a[i][j];
x[i] = (temp / a[i][i]);
}
return 0;
}
求解异或方程组
经常需要枚举自由元
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define nmax 35
using namespace std;
int a[nmax][nmax];
int x[nmax];
int hashback[nmax][nmax];
int free_x[nmax];
char mp[nmax][nmax];
int ans1,ans2;
int equ,var;
int Gauss(){
int max_r;
int col=0,num = 0;
int k;
for(int i = 0;i<=var;++i) x[i] = free_x[i] = 0;
for(k = 0;k < equ && col < var;k++,col++){
max_r=k;
for(int i=k+1;i<equ;i++){
if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
}
if(max_r!=k){
for(int j=k ;j<var+1;j++) swap(a[k][j],a[max_r][j]);
}
if(a[k][col]==0){
free_x[num++] = col;
k--; continue;
}
for(int i=k+1;i<equ;i++){
if(a[i][col]!=0){
for(int j=col;j<var+1;j++){
a[i][j]^=a[k][j];;
}
}
}
}
for(int i = k;i<equ;++i){
if(a[i][col] != 0) return -1;
}
if(k < var) return var - k;
for(int i = var - 1; i >= 0; i--){
x[i]=a[i][var];
for(int j = i + 1; j < var; j++){
x[i] ^= ( a[i][j] && x[j]);
}
}
return 0;
}
//参数n是自由元的个数,ans保存最后的最优解。
void enum_freex(int n,int & ans){
int num = (1<<(n));
ans = 1e9+7;
for(int i = 0;i<num;++i){
int cnt = 0;
for(int j = 0;j<n;++j){
if(i&(1<<j)){
cnt++;
x[free_x[j]] = 1;
}
else x[free_x[j]] = 0;
}
for(int k = var-n-1;k>=0;--k){// 没有自由元的最下面一行
int index = 0;
for(index = k;k<var;index++){// 在当前行找到第一个非0自由元(如果存在的话)
if(a[k][index]) break;
}
x[index] = a[k][var];
for(int j = index+1;j<var;++j){// 向后依次计算出结果
if(a[k][j]) x[index] ^= x[j];
}
cnt += x[index]; // 如果结果为1,则统计
}
ans = min(ans,cnt);
}
}
void init()
{
memset(a, 0, sizeof(a));
memset(x, 0, sizeof(x));
for(int i=0;i<equ;i++)
{
a[i][i]=1;
if(i+1<var){
a[i+1][i]=1;
a[i][i+1]=1;
}
}
}
int main()
{
equ=20;
var=20;
init();
for(int i=0;i<20;i++)
{
scanf("%d",&a[i][20]);
}
int ans=0;
enum_freex(Gauss(),ans);
cout<<ans<<endl;
}
经典例题:
异或方程组
POJ 1830 开关问题 (高斯消元)
POJ 3185 The Water Bowls 【一维开关问题 高斯消元+枚举自由元求最小值】
POJ 1681 Painter's Problem (高斯消元)
同余方程组
POJ2065 :SETI ( 高斯消元解同余方程组)
POJ 2947 Widget Factory (高斯消元解同余线性方程)
















