题意:将下图中的格子由初始状态变为全黄,最少需要多少步。
题解:先确定自由变量,然后枚举自由变量的值,注意剪枝。
#include<cmath>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
#define MAXN 230
int a[MAXN][MAXN], b[MAXN];
int index[MAXN], flag[MAXN]; //flag[i]==1表示b[i]是自由变量, index[i]记录第i个自由变量的下标
char str[MAXN];
int n, fnum, order; //fnum表示自由变量的数量,order是化简之后的举证的秩
int ans;
int abl ( int x )
{
return x >= 0 ? x : -x;
}
void Debug ( )
{
int i , j;
printf("Debug\n");
for ( i = 0; i < n; i++ )
{
for ( j = 0; j <= n; j++ )
printf("%d ",a[i][j]);
printf("\n");
}
}
/* x0 x1 x2 x3 x4 x5 b
0 0 1 0 1 1 1 1
1 0 0 0 0 1 0 1
2 0 0 0 0 0 1 0
3 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0
以此矩阵为例矩阵简单推导一下,便可得下面的求值函数
order = 2, n = 6;
x0, x2, x3 是自由变量;
先求x5: i = order-1 = 2, j = x + 1 = 6
······
*/
int cal ()
{
int i, j, x, sum = 0;
x = n - 1;
for ( i = order - 1; i >= 0; i-- )
{
while ( flag[x] && x >= 0 )
sum += b[x--];
if ( x >= 0 )
{
b[x] = a[i][n];
for ( j = x + 1; j < n; j++ )
b[x] ^= ( a[i][j] && b[j] );
sum += b[x--];
}
}
return sum;
}
void dfs ( int k, int cnt )
{
if ( cnt >= ans ) //剪枝
return;
if ( k >= fnum )
{
int tmp = cal();
if ( ans > tmp ) ans = tmp;
return;
}
b[index[k]] = 0;
dfs ( k + 1, cnt );
b[index[k]] = 1;
dfs ( k + 1, cnt + 1 );
}
int Gauss ()
{
int i, j, row, col, mr;
row = col = fnum = 0;
while ( row < n && col < n )
{
mr = row;
for ( i = row + 1; i < n; i++ )
if ( abl(a[i][col]) > abl(a[mr][col]) ) mr = i;
if ( mr != row )
for ( j = col; j <= n; j++ )
swap ( a[mr][j], a[row][j] );
if ( a[row][col] == 0 )
{
flag[col] = 1;
index[fnum++] = col;
col++; continue;
}
for ( i = row + 1; i < n; i++ )
{
if ( a[i][col] == 0 ) continue;
for ( j = col + 1; j <= n; j++ )
a[i][j] ^= a[row][j];
}
row++; col++;
}
//Debug();
order = row;
for ( i = row; i < n; i++ )
if ( a[i][n] ) return -1;
ans = MAXN;
dfs ( 0, 0 );
return ans;
}
void init ()
{
int i, j, k = n * n;
int t1, t2, t3, t4;
for ( i = 0; i < k; i++ )
{
t1 = i / n;
t2 = i % n;
for ( j = 0; j < k; j++ )
{
t3 = j / n;
t4 = j % n;
if ( abl(t1-t3) + abl(t2-t4) <= 1 )
a[i][j] = 1;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while ( t-- )
{
scanf("%d",&n);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(flag,0,sizeof(flag));
init();
int i, j, k, res;
k = n; n = n * n; i = 0;
while ( k-- )
{
scanf("%s",str);
for ( j = 0; str[j] != '\0'; j++ )
{
if ( str[j] == 'w' ) a[i][n] = 1;
i++;
}
}
//Debug();
res = Gauss ();
if ( res == -1 ) printf("inf\n");
else printf("%d\n",res);
}
}