複雜度(
過程:先將增廣矩陣轉上三角矩陣,然後解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;
}