题目大意:类似于POJ 1222,就是把开关灯变成了涂颜色。给你一个带颜色的矩阵,颜色只可能是白色或者黄色。涂一个块他的相邻的块都会改变颜色(上下左右的块),问最少多少步能把这个矩阵涂成黄色。
解题思路:这是一类问题,前面处理类似于POJ 1222,就是用异或方程组表状态,而后高斯消元,但是这个异或方程组用高斯消元后得到的未必有确定的解,也就是出现了自由元的状况。不同于线性方程组,异或方程组只存在0,1两种状态,也就是说可以通过给每个自由元赋值的方法来找最优解。题解一般都是用的状态压缩,我看不懂那个,而且他的代码还有点问题(这里说的POJ 3185),虽然ac了。想到dfs也可以达到相同效果,而且时间复杂度也不会因此提高,所以改写了一下,ac了POJ 3185,之后试了试这个题,完善了一下代码,也ac了,由于这个题目情况分的更加具体,就先写的这个题目。当然,肯定是状态压缩写起来更简短,但是dfs我懂啊......
ac 代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cmath>
#define maxn 510
#define INF 1e9
using namespace std;
int a[maxn][maxn];
int x[maxn];
int xx[4]={0,0,1,-1};
int yy[4]={1,-1,0,0};
int tot,var;
int rfree[maxn];
int ans;
int n;
int getmark(int r,int c){
if (r>=1&&r<=n&&c>=1&&c<=n){
return n*(r-1)+c;
}
return -1;
}
void geta(int i,int j){
int mark1=getmark(i,j);
a[mark1][mark1]=1;
for (int k=0;k<4;k++){
int nx=i+xx[k];
int ny=j+yy[k];
int mark2=getmark(nx,ny);
if (mark2!=-1){
a[mark2][mark1]=1;
}
}
}
int gauss(){
int maxr;
int c=1;
int k,i,j;
int num=0;
for (k=1;k<=tot&&c<=var;k++,c++){
maxr=k;
if (!a[k][c]){
for (i=k+1;i<=tot;i++)if (a[i][c]){
maxr=i;
break;
}
if (maxr!=k)for (i=c;i<=var+1;i++)swap(a[k][i],a[maxr][i]);
}
if (a[k][c]==0){
k--;
rfree[++num]=c;
continue;
}
for (i=k+1;i<=tot;i++){
if (a[i][c]){
for (j=c;j<=var+1;j++)a[i][j]^=a[k][j];
}
}
}
for (i=k;i<=tot;i++)if (a[i][var+1])return -1;
if (k-1<var)return var-k+1;
for (i=var;i>=1;i--){
x[i]=a[i][var+1];
for (j=i+1;j<=var;j++){
if (a[i][j]*x[j]){
x[i]^=x[j];
}
}
}
return 0;
}
void dfs(int s,int step){
int i,j,k;
if (s==0){//得到的结果唯一,不用继续dfs
int cnt=0;
for (i=1;i<=var;i++){
cnt+=x[i];
}
ans=min(ans,cnt);
}
else {
for (i=0;i<=1;i++){
x[rfree[step]]=i;
if (step==s){
for (j=var;j>=1;j--){
bool flag=1;
for (k=1;k<=s;k++){
if (j==rfree[k]){
flag=0;
break;
}
}
if (flag){
x[j]=a[j][var+1];
for (k=j+1;k<=var;k++){
if (x[k]*a[j][k]){
x[j]^=x[k];
}
}
}
}
int cnt=0;
for (j=1;j<=var;j++){
cnt+=x[j];
}
ans=min(ans,cnt);
}
else dfs(s,step+1);
}
}
}
int main(){
int t,i,j,k,l,cas=0;
char fun[maxn];
scanf("%d",&t);
while (t--){
memset (a,0,sizeof(a));
scanf("%d",&n);
l=0;
for (i=1;i<=n;i++){
scanf("%s",&fun);
for (j=1;j<=n;j++){
a[++l][n*n+1]=(fun[j-1]=='w')?1:0;
}
}
for (i=1;i<=n;i++){
for (j=1;j<=n;j++){
geta(i,j);
}
}
ans=INF;
tot=var=n*n;
int temp=gauss();
if (temp!=-1){
dfs(temp,1);
printf("%d\n",ans);
}
else printf("inf\n");
}
}