zoj 3353 Chess Board 高斯消元

高斯消元其本应用:

这题是要枚举自由元的;


#include<iostream>
#include<cstring>
#include<cstdio>
#define M 250
using namespace std;

int mat[M][M], ans[M], rem[M];
int id[20][20], num;
int n, m;
int dx[8] = {-1,-1,-1,0,0,1,1,1};
int dy[8] = {-1,0,1,-1,1,-1,0,1};
int d[4][5] = {1,3,4,6,-1,0,1,3,4,5,1,2,3,4,6,1,2,3,6,7}; //每一种pattern的走法;

bool inside( int i, int j )
{
	if( i >= 0 && i < n && j >= 0 && j < m )
		return 1;
	return 0;
}
void init( int a )             //初始化矩阵
{
	int en, u, v, x, y, w;
	memset( mat, 0, sizeof(mat) );
	if( a ) en = 5;
	else en = 4;
	for( int i = 0; i < n; i++ )
		for( int j = 0; j < m; j++ ){
			u = id[i][j];
			mat[u][u] = 1;
			mat[u][num] = rem[u];
			for( int k = 0; k < en; k++ ){
				w = d[a][k];
				x = i + dx[w];
				y = j + dy[w];
				if( inside( x, y ) ){
					v = id[x][y];
					mat[v][u] = 1;
				}
			}
		}
}

int cal( int row )
{
	for( int i = row-1; i >= 0; i-- ){
		ans[i] = mat[i][num];
		for( int j = i+1; j < num; j++ )
			ans[i] ^= mat[i][j]*ans[j];
	}
	int sum = 0;
	for( int i = 0; i < num; i++ )
		sum += ans[i];
	return sum;
}
int gauss( int aa )
{
	init(aa);
	int row = 0, col = 0;
	int i, j, a, b;
	while( row < num && col < num ){
		for( i = row; i < num; i++ )
			if( mat[i][col] ) break;
		if( i == num ){
			col++; continue;
		}
		if( i != row ){
			for( j = col; j <= num; j++ )
				swap( mat[i][j], mat[row][j] );

		}
		if( row != col ){           //列交换相当于把变量的位置交换,‌不影响结果。是为了方便把所有自由元排在后面
			for( j = 0; j < num; j++ )
				swap( mat[j][row], mat[j][col] );
		}
		for( i = row + 1; i < num; i++ ){
			if( mat[i][row] == 0 ) continue;
			for( j = row; j <= num; j++ ){
				mat[i][j] ^= mat[row][j];     //这里的异或操作只适用于只有0和1的情况
			}
		}
		row++; col++;
	}
	for( i = row; i < num; i++ )
		if( mat[i][num] ) return -1;
	int free = num - row;
	int len = 1<<free;
	a = M;
	for( i = 0; i < len; i++ ){    //枚举自由元的答案
		for( j = 0; j < free; j++ )
			ans[num-j-1] = (i&(1<<j)) != 0;
		b = cal( row );
		a = min( a, b );
	}
	return a;
}
int main()
{
	char str[M];
	int ma, k, temp;
	while( scanf( "%d%d", &n, &m ) == 2 ){
		if( !n && !m ) break;
		num = 0;
		for( int i = 0; i < n; i++ ){
			scanf( "%s", str );
			for( int j = 0; j < m; j++ ){
				rem[num] = (str[j] == '1');
				id[i][j] = num++;
			}
		}
		ma = M;k = -1;
		for( int i = 0; i < 4; i++ ){
			temp = gauss( i );
			if( temp != -1 && temp < ma ){
				ma = temp;
				k = i+1;
			}
		}
		if( ma == M )
			printf( "Impossible\n" );
		else{
			printf( "%d %d\n", k, ma );
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值