高斯消元
一:求行列式
1除法
double gauss(){//高斯消元求行列式
int max_row;
for(int row = 1, col = 1; row <= n && col <= n; row++, col++){
//找到当前列绝对值最大的行
max_row = row;
for(int i = row + 1; i <= n; i++) if(fabs(a[i][col]) > fabs(a[max_row][col] + eps)) max_row = i;
if(fabs(a[max_row][col] < eps)) {return 0;}//有一个0, 行列式为0
//交换绝对值最大的行/ 减小除法的精度损失
if(row != max_row){
for(int j = 1; j <= n; j++) swap(a[row][j], a[max_row][j]);
}
//消去当前列(只消下面行的)
for(int i = row + 1; i <= n; i++){
double temp = a[i][col] / a[row][col];
for(int j = col; j <= n; j++){
a[i][j] -= temp * a[row][j];
}
}
}
double ans = 1;
for(int i = 1; i <= n; i++) ans = ans * a[i][i];
return ans;
}
2逆元
ICPC 2021济南 J
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100 + 10;
const ll mod = 1e9 + 7;
ll a[N][N];
int n;
ll qpow(ll base, ll pow, ll mod){
ll ans = 1;
while(pow){
if(pow & 1) ans = ans * base % mod;
base = base * base % mod;
pow >>= 1;
}
return ans;
}
ll gauss_det_inv(ll a[][N], int n, ll mod){//高斯消元求行列式(逆元)
int flag = 1;
for(int row = 1, col = 1; row <= n && col <= n; row++, col++){
int max_row = row;
//排除0的情况
for(int i = row; i <= n; i++){
if(a[i][col] != 0) {max_row = i; break;}
}
if(row != max_row){
for(int j = 1; j <= n; j++) swap(a[row][j], a[max_row][j]);
flag = -flag;//交换行列式两行, 行列式值取反
}
//做除法
ll inv = qpow(a[row][col], mod - 2, mod);
for(int i = row + 1; i <= n; i++){
ll temp = a[i][col] * inv % mod;
for(int j = col; j <= n; j++){
a[i][j] = ((a[i][j] - temp * a[row][j]) % mod + mod) % mod;
}
}
}
ll ans = 1;
for(int i = 1; i <= n; i++){
ans = ans * a[i][i] % mod;
}
return (ans * flag % mod + mod) % mod;
}
char str[10010];
ll get_det(ll mod){
ll ret = 0;
int len = strlen(str + 1);
for(int i = 1; i <= len; i++){
ret = (ret * 10 + (str[i] - '0')) % mod;
}
return ret;
}
void solve(){
scanf("%d", &n);
scanf("%s", str + 1);
ll det = get_det(mod);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
scanf("%lld", &a[i][j]);
}
}
ll ans = gauss_det_inv(a, n, mod);
if(ans == det)printf("+\n");
else printf("-\n");
}
int main() {
int t = 1;
scanf("%d", &t);
while(t--)solve();
return 0;
}
3解线性方程组
1.1: 求具体的解
(1)唯一解
void gauss(double mat[N][N], double extra[N]/*矩阵的增广部分*/, int rank/*矩阵的秩*/){//化为对角矩阵
//数据保证唯一解
int maxRow;
for(int row = 1, col = 1; row <= rank && col <= rank; row++, col++){
//找到当前列绝对值最大的行
maxRow = row;
for(int i = row + 1; i <= rank; i++) if(fabs(mat[i][col]) > fabs(mat[maxRow][col])) maxRow = i;
//交换绝对值最大的行/ 减小除法的精度损失
if(row != maxRow){
for(int j = 1; j <= rank; j++) swap(mat[row][j], mat[maxRow][j]);
swap(extra[row], extra[maxRow]);
}
for(int i = 1; i <= rank; i++){
if(i == row) continue;
double rate = mat[i][col] / mat[row][col];
for(int j = col; j <= rank; j++){
mat[i][j] -= rate * mat[row][j];
}
extra[i] -= rate * extra[row];
}
}
//除掉系数
for(int i = 1; i <= rank; i++){
extra[i] /= mat[i][i];
}
}
#include <bits/stdc++.h>
using namespace std;
const int N = 15;
const double eps = 1e-8;
int n, m;
double a[N][N];
double mat[N][N], extra[N];//矩阵的增广部分
void gauss(double mat[N][N], double extra[N]/*矩阵的增广部分*/, int rank/*矩阵的秩*/){//化为对角矩阵
//数据保证唯一解
int maxRow;
for(int row = 1, col = 1; row <= rank && col <= rank; row++, col++){
//找到当前列绝对值最大的行
maxRow = row;
for(int i = row + 1; i <= rank; i++) if(fabs(mat[i][col]) > fabs(mat[maxRow][col])) maxRow = i;
//交换绝对值最大的行/ 减小除法的精度损失
if(row != maxRow){
for(int j = 1; j <= rank; j++) swap(mat[row][j], mat[maxRow][j]);
swap(extra[row], extra[maxRow]);
}
for(int i = 1; i <= rank; i++){
if(i == row) continue;
double rate = mat[i][col] / mat[row][col];
for(int j = col; j <= rank; j++){
mat[i][j] -= rate * mat[row][j];
}
extra[i] -= rate * extra[row];
}
}
//除掉系数
for(int i = 1; i <= rank; i++){
extra[i] /= mat[i][i];
}
}
void solve(){
cin >> n;
for(int i = 1; i <= n + 1; i++){
for(int j = 1; j <= n; j++){
cin >> a[i][j];
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
mat[i][j] = 2 * (a[i + 1][j] - a[i][j]);
extra[i] += (a[i + 1][j] * a[i + 1][j] - a[i][j] * a[i][j]);
}
}
gauss(mat, extra, n);
for(int i = 1; i <= n; i++){
cout << fixed << setprecision(3) << extra[i]<< " ";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t = 1;
while(t--) solve();
return 0;
}
4异或方程组
1.1求解的个数
int gaussXor(int mat[N], int rank) {//化为对角矩阵
//由于异或只有0和1,所以将一行的状态压缩为一个二进制数,故mat只有一维
//将矩阵的增广部分压缩进mat的第0位
//Q: 为什么不是最高位
//A: 二进制数高位到低位权值递减, 只有当系数矩阵一行的所有数均为0时, 才考虑矩阵的增广部分是否为0
//返回值: 解的个数
int maxRow;
for (int row = 1; row <= rank; row++) {
//找到当前值最大的行
for (int i = row + 1; i <= rank; i++) {
if (mat[i] > mat[row]) swap(mat[i], mat[row]);
}
//判断接下来的行存在系数全为0的行
if (mat[row] == 0) { return 1 << (rank - row + 1); }
if (mat[row] == 1) { return 0; }
for (int bit = n; bit; bit--) {
if(mat[row] >> bit & 1) {
for (int i = 1; i <= rank; i++) {
if(i == row) continue;
if(mat[i] >> bit & 1) mat[i] ^= mat[row];
}
break;
}
}
}
return 1;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 15;
int n, m;
int mat[N];//矩阵的增广部分
int gaussXor(int mat[N], int rank) {//化为对角矩阵
//由于异或只有0和1,所以将一行的状态压缩为一个二进制数,故mat只有一维
//将矩阵的增广部分压缩进mat的第0位
//Q: 为什么不是最高位
//A: 二进制数高位到低位权值递减, 只有当系数矩阵一行的所有数均为0时, 才考虑矩阵的增广部分是否为0
//返回值: 解的个数
int maxRow;
for (int row = 1; row <= rank; row++) {
//找到当前值最大的行
for (int i = row + 1; i <= rank; i++) {
if (mat[i] > mat[row]) swap(mat[i], mat[row]);
}
//判断接下来的行存在系数全为0的行
if (mat[row] == 0) { return 1 << (rank - row + 1); }
if (mat[row] == 1) { return 0; }
for (int bit = n; bit; bit--) {
if(mat[row] >> bit & 1) {
for (int i = 1; i <= rank; i++) {
if(i == row) continue;
if(mat[i] >> bit & 1) mat[i] ^= mat[row];
}
break;
}
}
}
return 1;
}
void solve(){
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> mat[i];
}
for (int i = 1; i <= n; i++) {
int t;
cin >> t;
mat[i] ^= t;
mat[i] |= 1 << i;
}
int x, y;
while (cin >> x >> y && x && y) {
mat[y] |= 1 << x;
}
int ans = gaussXor(mat, n);
if(ans) cout << ans << endl;
else cout << "Oh,it's impossible~!!" << endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
5 求一组基, 并用这组基进行一系列操作
ACwing210 异或运算
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 510;
bool canGetZero = false;
int numOfBase;//最多能取到多少数
void gaussXor (vector<ll>& mat, int n) {
//此题中高斯消元的主要作用是 得到一组线性无关的基
int maxRow;
numOfBase = n;
for (int row = 1; row <= n; row++) {
maxRow = 0;
for (int i = row; i <= n; i++) {
if (!maxRow || mat[i] > mat[maxRow]) {
maxRow = i;
}
}
if (mat[maxRow] == 0) {canGetZero = true; numOfBase = row - 1; return;}
swap(mat[row], mat[maxRow]);
for (int bit = 60; bit >= 0; bit--) {
if (mat[row] >> bit & 1) {
for (int i = 1; i <= n; i++) {
if (i == row) continue;
if (mat[i] >> bit & 1) mat[i] ^= mat[row];
}
break;
}
}
}
}
void solve(int cas) {
canGetZero = false;
cout << "Case #" << cas << ":" << endl;
int n;
cin >> n;
vector<ll> mat(n + 1);
for (int i = 1; i <= n; i++) {
cin >> mat[i];
}
gaussXor(mat, n);
int q;
cin >> q;
for (int i = 1; i <= q; i++) {
ll k;
cin >> k;
k--;
if (!canGetZero) k++;
ll ans = 0;
if (k >= (1ll << numOfBase)) cout << -1 << endl;
else {
for (int i = 0; i < numOfBase; i++) {
if (k >= (1ll << (numOfBase - 1 - i))) {
k -= (1ll << (numOfBase - 1 - i));
ans ^= mat[i + 1];
}
}
cout << ans << endl;
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
for(int i = 1; i <= t; i++) solve(i);
return 0;
}