HYSBZ/BZOJ 3503 和谐矩阵 - 高斯约当消元异或方程
Solution 1:
把矩阵中的每一个元素看作未知数,根据元素之间的互相影响列方程,方程大小为 (n*m,n*m)。如果有不定解怎么办呢?
1. dfs暴力枚举每一个不定解。肯定要TLE
2. 在每行确定解的时候,强制性设定这行的所有不定解为1 ,继续回代,直到出答案。 好像数据挺水,O((nm)3 )勉强能过。
1.代码,但要T
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1600
int dir[10][3]={{0,0},{0,1},{0,-1},{1,0},{-1,0}};
int n,m;
int a[MAXN+10][MAXN+10],id[MAXN+10][MAXN+10],x[MAXN+10],p;
void Structure()
{
int x,y;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
id[i][j]=(i-1)*m+j;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<5;k++){
x=i+dir[k][0],y=j+dir[k][1];
if(x>=1&&x<=n&&y>=1&&y<=m)
a[id[x][y]][id[i][j]]=1;
}
}
void GJ_elimination(int equ,int var,int &row,int &col)
{
int mx;
for(row=col=1;row<=equ&&col<=var;row++,col++){
mx=row;
for(int i=row+1;i<=equ;i++){
if(a[i][col]>a[mx][col])
mx=i;
if(a[mx][col]==1)
break;
}
if(mx!=row)
swap(a[row],a[mx]);
if(a[row][col]==0){ //本题有唯一解,这句if可以不要
row--;
continue;
}
for(int i=1;i<=equ;i++){
if(i==row||a[i][col]==0)
continue;
for(int j=var+1;j>=1;j--)
a[i][j]^=a[row][j];
}
}
}
int GJ_Judge(int equ,int var,int row,int col)
{
if(row<=var)
return row;
for(int i=row-1;i>=1;i--)
x[i]=a[i][var+1];
return 0;
}
int Gauss_Jordan(int equ,int var)
{
int row,col;
GJ_elimination(equ,var,row,col);
return GJ_Judge(equ,var,row,col);
}
void print()
{
for(int i=1;i<=n*m;i++){
printf("%d",x[i]);
if(i%m==0) printf("\n");
else printf(" ");
}
}
bool check()
{
int cnt=0,tmp;
for(int i=p-1;i>=1;i--){
tmp=0;
for(int j=i+1;j<=n*m;j++)
if(a[i][j])
tmp^=x[j];
x[i]=a[i][n*m+1]^tmp;
if(!x[i]) cnt++;
}
for(int i=p;i<=n*m;i++)
if(!x[i]) cnt++;
if(cnt==n*m) return false;
else return true;
}
void dfs(int u)
{
if(u>n*m){
if(check()){
print();
exit(0);
}
return ;
}
x[u]=1; dfs(u+1);
x[u]=0; dfs(u+1);
}
int main()
{
scanf("%d%d",&n,&m);
Structure();
p=Gauss_Jordan(n*m,n*m);
if(!p)
print();
else
dfs(p);
}
2.代码 by Liu Junhao 这是他关于这道题的blog
void gauss_jordan(){
int row,col,i,j,cnt;
for(row=col=1;row<=equ&&col<=var;row++,col++){
if(!a[row][col])
for(i=row+1;i<=equ;i++)
if(a[i][col]){
swap(a[row],a[i]);
break;
}
if(!a[row][col]){
row--;
continue;
}
for(i=1;i<=equ;i++)
if(i!=row&&a[i][col])
for(j=var+1;j>=col;j--)
a[i][j]^=a[row][j];
}
row--;
for(i=row;i;i--){
cnt=0;
for(j=i;j<=var;j++)
if(a[i][j]){
if(!vis[j])
cnt++;
else
a[i][var+1]^=x[j],a[i][j]=0;
}
for(j=i;j<=var;j++)
if(a[i][j]){
if(--cnt)
x[j]=1,a[i][var+1]^=1;
else
x[j]=a[i][var+1];
vis[j]=1;
}
}
}
void print(){
int i,j;
for(i=1;i<=n;i++){
for(j=1;j<=m;j++)
printf("%d ",x[(i-1)*m+j]);
puts("");
}
}
int main()
{
read();
gauss_jordan();
print();
}
Solution 2:
将矩阵第一行的m个元素看作未知数,记为x1 ~ xm ,由元素之间的互相影响可以推出其后的每个元素关于x1 ~ xm 的关系式,最后由剩下的m个影响关系得到m个关于x1 ~ xm 的方程,用高斯消元求解,O(m3 )的复杂度。
对于不定解的处理仍然有solution 1 中的两种方案,但方案1可用了,不会再超时,而且较solution快了不知多少倍。
可惜solution 2的代码太长,把Special Judge()去掉的话会好看一些
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 40
int dir[10][3]={{-2,0},{-1,0},{-1,-1},{-1,1}};
int dir2[10][3]={{0,0},{0,1},{0,-1},{-1,0}};
int n,m,a[MAXN+10][MAXN+10],x[MAXN+10];
int p[MAXN+10][MAXN+10][MAXN+10],cntx,ans[MAXN+10][MAXN+10];
void print();
void Represent()
{
int x,y;
for(int j=1;j<=m;j++)
p[1][j][j]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++){
x=i+dir[k][0],y=j+dir[k][1];
if(!(x>=1&&x<=n&&y>=1&&y<=m))
continue;
for(int t=1;t<=m;t++)
p[i][j][t]^=p[x][y][t];
}
}
}
void Structure()
{
int x,y;
for(int j=1;j<=m;j++){
for(int k=0;k<4;k++){
x=n+dir2[k][0],y=j+dir2[k][1];
if(!(x>=1&&x<=n&&y>=1&&y<=m))
continue;
for(int t=1;t<=m;t++)
a[j][t]^=p[x][y][t];
}
}
}
void GJ_elimination(int equ,int var,int &row,int &col)
{
int mx;
for(row=col=1;row<=equ&&col<=var;row++,col++){
mx=row;
for(int i=row+1;i<=equ;i++){
if(a[i][col]>a[mx][col])
mx=i;
if(a[mx][col]==1)
break;
}
if(mx!=row)
swap(a[mx],a[row]);
if(a[row][col]==0){
row--;
continue;
}
for(int i=1;i<=equ;i++){
if(i==row||a[i][col]==0)
continue;
for(int j=1;j<=var+1;j++)
a[i][j]^=a[row][j];
}
}
}
int Gauss_Jordan(int equ,int var)
{
int row,col;
GJ_elimination(equ,var,row,col);
if(row<=var) return var-row+1;
else return 0;
}
bool Judge()
{
int cnt0=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
for(int k=1;k<=m;k++)
if(p[i][j][k])
ans[i][j]^=x[k];
if(!ans[i][j])
cnt0++;
}
if(cnt0==n*m) return false;
else return true;
}
bool check(int cntx)
{
int tmp;
for(int i=m-cntx;i>=1;i--){
tmp=0;
for(int j=i+1;j<=m;j++)
if(a[i][j])
tmp^=x[j];
x[i]=a[i][m+1]^tmp;
}
return Judge();
}
bool SpecialJudge()
{
int dr[10][6]={{0,0},{1,0},{-1,0},{0,1},{0,-1}};
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int tmp=0;
for(int k=0;k<5;k++){
int x=i+dr[k][0],y=j+dr[k][1];
if(x>=1&&x<=n&&y>=1&&y<=m){
tmp^=ans[x][y];
}
}
if(tmp){
printf("%d %d\n",i,j);
return false;
}
}
}
return true;
}
void print()
{
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d ",ans[i][j]);
puts("");
}
/*if(SpecialJudge())
printf("Right\n");
else
printf("Wrong\n");*/
}
void dfs(int u)
{
if(u>m){
if(check(cntx)){
print();
exit(0);
}
return ;
}
x[u]=1; dfs(u+1);
x[u]=0; dfs(u+1);
}
int main()
{
scanf("%d%d",&n,&m);
Represent();
Structure();
cntx=Gauss_Jordan(m,m);
if(cntx)
dfs(m-cntx+1);
else{
for(int i=1;i<=m;i++)
x[i]=a[i][m+1];
print();
}
return 0;
}