复杂度(
O(n3)
O
(
n
3
)
过程:先将增广矩阵转上三角矩阵,然后解x[i];
模板:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#include<algorithm>
using namespace std;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
ll lcm(ll a,ll b)
{
return a/gcd(a,b)*b;
}
const int maxn=105;
int equ,var;
int x[maxn];
int a[maxn][maxn];//增广矩阵
int free_x[maxn];
int free_num=0;
int Gauss()//O(n^3)
{
int col,row,max_r;
col=0;row=0;
free_num=0;
for(;row<equ&&col<var;row++,col++)
{
max_r=row;
for(int i=row+1;i<equ;i++)//找出列中最大的行,然后交换
{
if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
}
if(max_r!=row)
{
for(int i=col;i<var+1;i++) swap(a[row][i],a[max_r][i]);
}
if(a[row][col]==0)//如果本列row行一下全0则不需要在处理,直接下一列
{
row--;
free_x[free_num++]=col;//自由变元
continue;
}
for(int i=row+1;i<equ;i++)//初等矩阵变换,目的上三角矩阵
{
if(a[i][col]!=0)
{
int t=lcm(abs(a[i][col]),abs(a[row][col]));
int ta=t/a[row][col];
int tb=t/a[i][col];
if(a[row][col]*a[i][col]>0)tb=-tb;
for(int j=col;j<var+1;j++)
{
a[i][j]=a[i][j]*tb+a[row][j]*ta;
}
}
}
}
for(int i=row;i<equ;i++)//row行一下肯定已经全0了,如果var不为0,则无解
{
if(a[i][col]!=0)return -1;
}
if(row<var)return var-row;//有多少行0既有多少个自由元
for(int i=var-1;i>=0;i--)//解上三角矩阵,自下而上
{
int t = a[i][var];
for(int j=i+1;j<var;j++)
{
t-=a[i][j]*x[j];
}
if(t%a[i][i]!=0)return -2;
else x[i]=t/a[i][i];
}
return 0;
}
int main()
{
while(scanf("%d%d",&equ,&var)!=EOF)
{
memset(a,0,sizeof a);
memset(x,0,sizeof x);
memset(free_x,0,sizeof free_x);
for(int i=0;i<equ;i++)
{
for(int j=0;j<=var;j++)
{
scanf("%d",&a[i][j]);
}
}
int free=Gauss();
if(free==-1)
{
printf("无解\n");
}
else if(free==-2)
{
printf("无整数解,有浮点数解\n");
}
else if(free>0)
{
printf("自由元个数为%d\n",free);
}
else
{
for(int i=0;i<var;i++)
{
printf("x%d: %d\n",i+1,x[i]);
}
}
}
return 0;
}
poj1830
题解:构造成模2的解方程组。做几个等价即可,乘法等价乘&&,加法减法等价乘^
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#include<algorithm>
using namespace std;
const int maxn=105;
int equ,var;
int x[maxn];
int a[maxn][maxn];//增广矩阵
int free_x[maxn];
int free_num;
int Gauss()//O(n^3)
{
int col,row,max_r;
col=0;row=0;
free_num=0;
for(;row<equ&&col<var;row++,col++)
{
max_r=row;
for(int i=row+1;i<equ;i++)//找出列中最大的行,然后交换
{
if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
}
if(max_r!=row)
{
for(int i=col;i<var+1;i++) swap(a[row][i],a[max_r][i]);
}
if(a[row][col]==0)//如果本列row行一下全0则不需要在处理,直接下一列
{
row--;
free_x[free_num++]=col;//记录自由变元
continue;
}
for(int i=row+1;i<equ;i++)//初等矩阵变换,目的上三角矩阵
{
if(a[i][col]!=0)
for(int j=col;j<var+1;j++)
{
a[i][j]=a[i][j]^a[row][j];
}
}
}
for(int i=row;i<equ;i++)//row行一下肯定已经全0了,如果var不为0,则无解
{
if(a[i][col]!=0)return -1;
}
if(row<var)return var-row;//有多少行0既有多少个自由元
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;
}
int start[40],end[40];
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(a,0,sizeof a);
memset(x,0,sizeof x);
equ=var=n;
for(int i=0;i<n;i++)
{
scanf("%d",&start[i]);
}
for(int i=0;i<n;i++)
{
scanf("%d",&end[i]);
}
int ca,cb;
while(scanf("%d%d",&ca,&cb))//题意ca变则cb变,即ans[cb]的结果受ca的影响
{
if(ca==0&&cb==0)break;
a[cb-1][ca-1]=1;//注意
}
for(int i=0;i<n;i++)
{
a[i][i]=1;
a[i][n]=(start[i]^end[i]);
}
int free=Gauss();
if(free==-1)
{
printf("Oh,it's impossible~!!\n");
}
else
{
printf("%d\n",1<<free);
}
}
return 0;
}
题意:对所有块涂颜色,只有黄白,每次涂一快,上下左右颜色反转,求最后涂成全黄要几步。
题解:构造高斯消元,求解中为1的个数。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#include<algorithm>
using namespace std;
const int maxn=255;
int equ,var;
int x[maxn];
int a[maxn][maxn];//增广矩阵
int free_x[maxn];
int free_num;
int Gauss()//O(n^3)
{
int col,row,max_r;
col=0;row=0;
free_num=0;
for(;row<equ&&col<var;row++,col++)
{
max_r=row;
for(int i=row+1;i<equ;i++)//找出列中最大的行,然后交换
{
if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
}
if(max_r!=row)
{
for(int i=col;i<var+1;i++) swap(a[row][i],a[max_r][i]);
}
if(a[row][col]==0)//如果本列row行一下全0则不需要在处理,直接下一列
{
row--;
free_x[free_num++]=col;//记录自由变元
continue;
}
for(int i=row+1;i<equ;i++)//初等矩阵变换,目的上三角矩阵
{
if(a[i][col]!=0)
for(int j=col;j<var+1;j++)
{
a[i][j]=a[i][j]^a[row][j];
}
}
}
for(int i=row;i<equ;i++)//row行一下肯定已经全0了,如果var不为0,则无解
{
if(a[i][col]!=0)return -1;
}
//注意我们这里把自由变元删掉
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;
}
char str[50][50];
int t,n;
void init()
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
int t=i*n+j;
a[t][t]=1;
if(i>0)a[(i-1)*n+j][t]=1;
if(j>0)a[i*n+j-1][t]=1;
if(i<n-1)a[(i+1)*n+j][t]=1;
if(j<n-1)a[i*n+j+1][t]=1;
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(a,0,sizeof a);
memset(x,0,sizeof x);
memset(free_x,0,sizeof free_x);
equ=var=n*n;
for(int i=0;i<n;i++)
{
scanf("%s",str[i]);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(str[i][j]=='y')
{
a[i*n+j][var]=0;
}
else
{
a[i*n+j][var]=1;
}
}
}
init();
int free=Gauss();
if(free==-1)
{
printf("inf\n");
}
else
{
int sum=0;
for(int i=0;i<var;i++){
if(x[i])sum++;
}
printf("%d\n",sum);
}
}
return 0;
}
上面的程序可能出错:
比较严谨的做法是:枚举自由变元求最小
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#include<algorithm>
using namespace std;
const int maxn=255;
int equ,var;
int x[maxn];
int a[maxn][maxn];//增广矩阵
int free_x[maxn];
int free_num;
int Gauss()//O(n^3)
{
int col,row,max_r;
col=0;row=0;
free_num=0;
for(;row<equ&&col<var;row++,col++)
{
max_r=row;
for(int i=row+1;i<equ;i++)//找出列中最大的行,然后交换
{
if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
}
if(max_r!=row)
{
for(int i=col;i<var+1;i++) swap(a[row][i],a[max_r][i]);
}
if(a[row][col]==0)//如果本列row行一下全0则不需要在处理,直接下一列
{
row--;
free_x[free_num++]=col;//记录自由变元
continue;
}
for(int i=row+1;i<equ;i++)//初等矩阵变换,目的上三角矩阵
{
if(a[i][col]!=0)
for(int j=col;j<var+1;j++)
{
a[i][j]=a[i][j]^a[row][j];
}
}
}
for(int i=row;i<equ;i++)//row行一下肯定已经全0了,如果var不为0,则无解
{
if(a[i][col]!=0)return -1;
}
//注意我们这里把自由变元删掉
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]);
}
}
int stat=1<<(var-row);//自由变元有 var-k 个
int res=1e9;
for(int i=0;i<stat;i++)//枚举所有变元
{
int cnt=0;
int index=i;
for(int j=0;j<var-row;j++)
{
x[free_x[j]]=(index&1);
if(x[free_x[j]]) cnt++;
index>>=1;
}
for(int j=row-1;j>=0;j--)
{
int tmp=a[j][var];
for(int l=j+1;l<var;l++)
if(a[j][l]) tmp^=x[l];
x[j]=tmp;
if(x[j])cnt++;
}
if(cnt<res)res=cnt;
}
return res;
}
char str[50][50];
int t,n;
void init()
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
int t=i*n+j;
a[t][t]=1;
if(i>0)a[(i-1)*n+j][t]=1;
if(j>0)a[i*n+j-1][t]=1;
if(i<n-1)a[(i+1)*n+j][t]=1;
if(j<n-1)a[i*n+j+1][t]=1;
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(a,0,sizeof a);
memset(x,0,sizeof x);
memset(free_x,0,sizeof free_x);
equ=var=n*n;
for(int i=0;i<n;i++)
{
scanf("%s",str[i]);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(str[i][j]=='y')
{
a[i*n+j][var]=0;
}
else
{
a[i*n+j][var]=1;
}
}
}
init();
int free=Gauss();
if(free==-1)
{
printf("inf\n");
}
else
{
printf("%d\n",free);
}
}
return 0;
}