传送门:POJ1681
题意:给定n*n矩阵,每个点要么为1,要么为0,当改变一个点的时候其上下左右四个点都会发生变化,问最少用多少步能使所有点都变成0.
思路:可以枚举第一行的状态求解,也可以用高斯消元法求解。
至于为什么能用高斯消元求解请戳这里
我是对着邝斌巨巨的博客敲得,敲完也不是很理解,直到看到了上面的博客才有些理解,不过高斯消元的回带过程完全搞不懂,可我明明是上学习期才学完的线性代数啊。。菜狗一条。。
代码:
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#define ll long long
#define pi acos(-1)
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define rep(i,x,n) for(int i=x;i<n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
using namespace std;
const int MAXN=310;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int n;
int mat[MAXN][MAXN];//要求解的增广矩阵
int x[MAXN];//解集
int free_x[MAXN];//标记是否是自由变元
int free_num;//自由变元的个数
// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,
//-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)
//有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var.
int gauss(int equ,int var)
{
int i,j,k;
int max_r;//当前列最绝对值大的行
int col;//当前列
free_num=col=0;
for(k=0;k<equ&&col<var;k++,col++)
{
max_r=k;
for(j=k+1;j<equ;j++)
if(abs(mat[j][col])>abs(mat[max_r][col]))
max_r=j;
if(max_r!=k)
for(j=col;j<=var;j++)
swap(mat[k][j],mat[max_r][j]);
if(mat[k][col]==0)//说明该col列第k行以下全是0了,则处理当前行的下一列.
{
k--;
free_x[free_num++]=col;
continue;
}
for(i=k+1;i<equ;i++)
{
if(mat[i][col])
{
for(j=col;j<=var;j++)
mat[i][j]^=mat[k][j];//异或是个思维点
}
}
}
for(i=k;i<equ;i++)
if(mat[i][var])
return -1;
int num=var-k;//自由变元的个数
int t=(1<<num),ans=inf;
for(i=0;i<t;i++)
{
int cnt=0,tmp=i;
for(j=0;j<num;j++)
{
x[free_x[j]]=(tmp&1);
if(tmp&1)cnt++;
tmp>>=1;
}
for(j=k-1;j>=0;j--)
{
tmp=mat[j][var];
for(int o=j+1;o<var;o++)
if(mat[j][o])tmp^=x[o];
x[j]=tmp;
if(x[j])cnt++;
}
ans=min(ans,cnt);
}
return ans;
}
void init()
{
memset(x,0,sizeof(x));
memset(mat,0,sizeof(mat));
memset(free_x,0,sizeof(free_x));
int t;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
t=n*i+j;
mat[t][t]=1;
if(i>0)mat[(i-1)*n+j][t]=1;
if(i<n-1)mat[(i+1)*n+j][t]=1;
if(j>0)mat[i*n+j-1][t]=1;
if(j<n-1)mat[i*n+j+1][t]=1;
}
}
int main()
{
int T;
cin>>T;
string s;
while(T--)
{
cin>>n;
init();
for(int i=0;i<n;i++)
{
cin>>s;
for(int j=0;j<n;j++)
{
if(s[j]=='w')mat[i*n+j][n*n]=1;
else mat[i*n+j][n*n]=0;
}
}
int ans=gauss(n*n,n*n);
if(ans==-1)
cout<<"inf\n";
else
cout<<ans<<endl;
}
return 0;
}
其实上面链接里的博客更好理解一些的。
点击打开链接 还有这一个,注释很详细。