poj1753--Flip Game(高斯消元问题2,枚举自由元的首杀)

Flip Game

Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d
& %I64u

Submit Status

Description

Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it‘s black or white side up. Each round you flip 3 to 5 pieces,
thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules:

  1. Choose any one of the 16 pieces.
  2. Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).

Consider the following position as an example:

bwbw

wwww

bbwb

bwwb

Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become:

bwbw

bwww

wwwb

wwwb

The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal.

Input

The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.

Output

Write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it‘s impossible to achieve the goal, then write the word "Impossible"
(without quotes).

Sample Input

bwwb
bbwb
bwwb
bwww

Sample Output

4

黑白棋翻转问题,搜索,枚举都可以做,这次用它来练习高斯消元做法

每个有关系的系数为1,每个棋子是否翻转确定了结果是0还是1,得到了异或方程组,使用高斯消元,找出自由元,然后转化为二进制后,枚举自由元,找出最优解。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define INF 0x3f3f3f3f
int Map[20][20] , a[20] , min1 , x[20] , freex[20] ;
char str[5][5] ;
void getMap(int k)
{
    int i , j ;
    memset(Map,0,sizeof(Map)) ;
    for(i = 0 ; i < 4 ; i++)
    {
        for(j = 0 ; j < 4 ; j++)
        {
            a[i*4+j] = (str[i][j] - '0') ^ k ;
            Map[i*4+j][i*4+j] = 1 ;
            if( i > 0 )
                Map[i*4+j][i*4+j-4] = 1 ;
            if( i < 3 )
                Map[i*4+j][i*4+j+4] = 1 ;
            if( j > 0 )
                Map[i*4+j][i*4+j-1] = 1 ;
            if( j < 3 )
                Map[i*4+j][i*4+j+1] = 1 ;
        }
    }
    return ;
}
void swap1(int p,int q)
{
    int j , temp ;
    temp = a[p] ;
    a[p] = a[q] ;
    a[q] = temp ;
    for(j = 0 ; j < 16 ; j++)
    {
        temp = Map[p][j] ;
        Map[p][j] = Map[q][j] ;
        Map[q][j] = temp ;
    }
    return ;
}
int solve()
{
    int i , j , k , t = 0 , num1 = 0 ;
    for(i = 0 ; i < 16 && t < 16 ; t++ , i++)
    {
        for(j = i ; j < 16 ; j++)
            if( Map[j][t] )
                break ;
        if( j == 16 )
        {
            freex[num1++] = t ;
            i-- ;
            continue ;
        }
        if( i != j )
            swap1(i,j) ;
        for(j = i+1 ; j < 16 ; j++)
        {
            if( Map[j][t] )
            {
                a[j] = a[j]^a[i] ;
                for(k = t ; k < 16 ; k++)
                    Map[j][k] = Map[j][k] ^ Map[i][k] ;
            }
        }
    }
    for( ; i < 16 ; i++)
        if( a[i] )
            return -1 ;
    if( num1 ) return num1 ;
    for(i = 15 ; i >= 0 ; i--)
    {
        x[i] = a[i] ;
        for(j = i+1 ; j < 16 ; j++)
            x[i] = x[i]^(Map[i][j]*x[j]) ;
    }
    return num1 ;
}
int f(int s)
{
    int i , j , k , key , ans , min1 = INF ;
    getMap(s) ;
    key = solve() ;
    ans = 0 ;
    if( key == 0 )
    {
        ans = 0 ;
        for(i = 0 ; i < 16 ; i++)
            ans += x[i] ;
        min1 = min(min1,ans) ;
    }
    else if( key > 0 )
    {
        int temp = 1<<key ;
        for(int t = 0 ; t < temp ; t++)
        {
            memset(x,0,sizeof(x)) ;
            ans = 0 ;
            for(j = 0 ; j < key ; j++)
                if( t & (1<<j) )
                {
                    x[ freex[j] ] = 1 ;
                    ans++ ;
                }
            for(i = 15 ; i >= 0 ; i--)
            {
                for(k = 0 ; k < 16 ; k++)
                    if( Map[i][k] )
                        break ;
                x[k] = a[i] ;
                for(j = k+1 ; j < 16 ; j++)
                    x[k] ^= (Map[i][j]*x[j]) ;
                ans += x[k] ;
            }
            min1 = min(min1,ans) ;
        }
    }
    return min1 ;
}
int main()
{
    int i , j , min1 = INF , k , ans , temp ;
    for(i = 0 ; i < 4 ; i++)
    {
        scanf("%s", str[i]) ;
        for(j = 0 ; j < 4 ; j++)
        {
            if( str[i][j] == 'b' )
                str[i][j] = '0' ;
            else
                str[i][j] = '1' ;
        }
    }
    ans = f(0) ;
    min1 = min(min1,ans) ;
    ans = f(1) ;
    min1 = min(min1,ans) ;
    if( min1 == INF )
        printf("Impossible\n") ;
    else
        printf("%d\n", min1) ;
    return 0;
}

时间: 2024-10-09 00:51:48

poj1753--Flip Game(高斯消元问题2,枚举自由元的首杀)的相关文章

POJ 1222【异或高斯消元|二进制状态枚举】

题目链接:[http://poj.org/problem?id=1222] 题意:Light Out,给出一个5 * 6的0,1矩阵,0表示灯熄灭,反之为灯亮.输出一种方案,使得所有的等都被熄灭. 题解:首先可以用高斯消元来做,对于每个点,我们列出一个方程,左边是某个点和它相邻的点,他们的异或值等于右边的值(灯亮为1 ,灯灭为0),然后求一个异或高斯消元就可以了.可以用bitset优化,或者__int128优化(其实unsigned就可以了). 还可以枚举第一行的按开关的状态共有1<<6中状态

NEFU 504 new Flip Game (高斯消元)

题目链接 题解:和 poj1753Filp game 差不多,区别在于t组数据并且翻转的时候多了一个左上角. #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <map> #includ

poj 1753 Flip Game 高斯消元

题目链接 4*4的格子, 初始为0或1, 每次翻转一个会使它四周的也翻转, 求翻转成全0或全1最少的步数. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include &

POJ 3185 The Water Bowls 高斯消元

高斯消元+位运算枚举自由变元 #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <set> #include <bitset> #include <queue> #include <stack> #include <string> #include <iostream> #i

poj 1753 Flip Game(高斯消元)

Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30805   Accepted: 13409 Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the

POJ 1753 Flip Game (高斯消元 枚举自由变元求最小步数)

题目链接 题意:4*4的黑白棋,求把棋全变白或者全变黑的最小步数. 分析:以前用状态压缩做过. 和上题差不多,唯一的不同是这个终态是黑棋或者白棋, 但是只需要把给的初态做不同的两次处理就行了. 感觉现在还只是会套模板,不能独立的思考,好伤心.... 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath&g

poj1753(高斯消元解mod2方程组)

题目链接:http://poj.org/problem?id=1753 题意:一个 4*4 的棋盘,初始时上面放满了黑色或白色的棋子.对 (i, j) 位置进行一次操作后 (i, j), (i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1) 位置的棋子会变成原来相反的状态.问最少需要多少步可以将棋盘上的棋子全部变成白色或者黑色. 思路:分别将棋子变成黑色和白色,然后再用高斯消元解,其中步数较小者即为答案. 注意不存在唯一解时需要枚举自由变元来取得最小步数.

高斯消元【转】

转载注明出处 高消一直是ACM中高层次经常用到的算法,虽然线性代数已经学过,但高消求解的问题模型及高消模板的应用变化是高消的最复杂之处. 先介绍一下高消的基本原理:引入互联网czyuan的帖子: 高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵. 高斯消元法的原理是: 若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程组. 所以我们可以用初等行变换把增广矩阵转换为行阶梯阵,然后回代求出方程的解. 以上是线性代数课的回顾,

【BZOJ 4171】 4171: Rhl的游戏 (高斯消元)

4171: Rhl的游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 74  Solved: 33[Submit][Status][Discuss] Description RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色 .每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子 ),黑变白,白变黑.RHL希望把所有格子都变成白色的.不幸