高斯消元(新)

之前的博客好像有点水

做法

高斯消元

上面已经讲过,另一种写法是先消成倒三角状,在从下往上一个个解出未知数。

对于无解的情况:

有n个未知数,大于n个方程发现后面的方程未知数元已经被消掉可是增广矩阵的右边还有值,则判无解。另外,消元时发现某一行所有元被消掉可是增广矩阵的右边还有值,则判无解。

对于有无穷解的情况:

从下往上解方程时发现可能有无穷解,那么先把可以求出解的方程算出来,再对那些还不能求出解的方程求解,如果发现系数为0,则就有无穷解

 

例题

Description

有一个有趣的手机游戏,有n*n个正方形的小按钮,有的按钮是黄色,有的按钮是白色。玩家的任务是通过点击按钮,让所有按钮都变成黄色,点按钮的次数越少,得分越高。 
但是按钮有个奇怪的特点,当你点击了坐标为(x,y)的按钮后,坐标为(x,y),(x+1,y),(x-1,y),(x,y-1),(x,y+1)的五个按钮会同时改变自身的颜色,是白色的变成黄色,黄色的变成白色。完成游戏最少需要点击多少次按钮呢?请找出答案。 
 

Input

第一行,一个整数n,表示有n*n个按钮。(1<=n<=40) 
接下来是一个由小写字母'y'和字符'w'构成的n*n的矩阵,描述了游戏开始时的情景。'y'表示该按钮式黄色,'w'表示该按钮式白色。

Output

如果能够完成游戏,输出一个整数,表示所需最小点击次数。 
如果无法完成游戏,输出"inf"

Sample Input

 

样例输入1:
2
yw
ww

样例输入2:

5
wwwww
wwwww
wwwww
wwwww
wwwww

 

Sample Output

 

样例输出1:
1

样例输出2:
15

直接高斯消元mod 2 方程组每一个格子只可能有5个格子通过操作使这个格子变换,所以时间复杂度是5n^2的

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 43;
int n;
int sum[MAXN*MAXN][MAXN*MAXN];
char s[MAXN];
int qz( int x , int y ){ return ( x - 1 ) * n + y ; }
int ans = 0x3f3f3f3f , tot[MAXN];
void dfs( int x , int now ){
    if( !x ){
        ans = min( ans , now );
        return ;
    }
    int k = 0;
    for( int i = x + 1 ; i <= n * n ; i ++ ){
        k = ( k + tot[i] * sum[x][i] % 2 ) % 2;
    }
    if( !sum[x][x] && k != sum[x][n*n+1] ){
        printf( "inf" );
        exit(0);
    }
    if( !sum[x][x] ){
        tot[x] = 1;dfs( x - 1, now + 1 );
        tot[x] = 0;dfs( x - 1 , now );
    }
    else if( sum[x][x] && k == sum[x][n*n+1] ){
        tot[x] = 0;dfs( x - 1 , now );
    }
    else{
        tot[x] = 1;dfs( x - 1 , now + 1 );
    }
}
int main(){
    scanf( "%d" , &n );
    for( int i = 1 ; i <= n ; i ++ ){
        scanf( "%s" , s );
        for( int j = 0 ; j < n ; j ++ ){
            if( s[j] == 'y' )
                sum[qz(i,j+1)][n*n+1] = 0;
            else sum[qz(i,j+1)][n*n+1] = 1;
        }
    }
    for( int i = 1 ; i <= n ; i ++ ){
        for( int j = 1 ; j <= n ;  j ++ ){
            if( i - 1 >= 1 ){
                sum[qz(i,j)][qz(i-1,j)] = 1;
            }
            if( j - 1 >= 1 )
                sum[qz(i,j)][qz(i,j-1)] = 1;
            sum[qz(i,j)][qz(i,j)] = 1;
            if( j + 1 <= n )
                sum[qz(i,j)][qz(i,j+1)] = 1;
            if( i + 1 <= n )
                sum[qz(i,j)][qz(i+1,j)] = 1;
        }
    }
    for( int i = 1 ; i <= n * n ; i ++ ){
        if( !sum[i][i] ){
            for( int j = i + 1 ; j <= n * n ; j ++ )
                if( sum[j][i] ){
                    for( int k = 1 ; k <= n * n + 1 ; k ++ )
                        swap( sum[i][k] , sum[j][k] );
                    break;
                }
        }
        for( int j = i + 1 ; j <= n * n ; j ++ ){
            if( sum[j][i] ){
                for( int k = 1 ; k <= n * n + 1 ; k ++ ){
                    sum[j][k] = ( sum[j][k] - sum[i][k] + 2 ) % 2;
                }
            }
        }
    }
    dfs( n * n  , 0 );
    printf( "%d" , ans );
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值