POJ1753 Flip Game【高斯消元法】

来源:互联网 发布:淘宝bug 编辑:程序博客网 时间:2024/05/22 11:54
题目链接:
http://poj.org/problem?id=1753

题目大意:
有一个 4*4 的棋盘,棋盘上有黑色和白色的格子,每一次你可以翻其中的一个格子,
个格子(x,y)如果被翻,那么对应位置为(x-1,y)、(x+1,y)、(x,y-1)、(x,y+1)
格子的颜色会变成相对的颜色,现在求将棋盘全部翻为白色格子或者是黑色格子用的最
少的步数是多少?如果无法把所有格子都翻为白色或者是黑色,那么输出 "Impossible"。

解题思路:
和 POJ1222 一样,一个格子变化最多改变 5 个格子,其中格子改变为 1,格子不改变
为 0,则每个位置上的格子向量中最多有 5 项为 1,其余为 0。这样 16 个位置的开
关向量构成一个 16*16 的格子矩阵 A[][]。用 A[][] 第16列 (即A[][N]) 的 16*1 向量来存
改变结果,A[i][N] 来表示第 i 个开关是否改变。然后用高斯消元求解。
无解输出"Impossible",有唯一解则求出解集中 1 的和。有无穷解则枚举自由变元来找
到最优解。
因为可以全部转为白色或是黑色,所以需要做两次高斯消元。

AC代码:
#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cmath>using namespace std;const int MAXN = 300;const int INF = 0xffffff0;int Equ,Var;int A[MAXN][MAXN];int X[MAXN];bool FreeX[MAXN];int FreeNum;int FreeOnly[MAXN];void Debug(){    for(int i = 0; i < Equ; ++i)    {        for(int j = 0; j < Var+1; ++j)            cout << A[i][j] << ' ';        cout << endl;    }}int GCD(int a,int b){    if(b == 0)        return a;    return GCD(b,a%b);}int LCM(int a,int b){    return a / GCD(a,b) * b;}int Gauss(){    int i,j,k;    int MaxRow;    int col;    int Lcm;    int ta,tb;    int temp;    int FreeXNum = 0;    int FreeIndex;    col = 0;    for(int i = 0; i <= Var; ++i)    {        X[i] = 0;        FreeX[i] = true;    }    for(k = 0; k < Equ && col < Var; ++k,++col)    {        MaxRow = k;        for(i = k+1; i < Equ; ++i)        {            if(abs(A[i][col]) > abs(A[MaxRow][col]))                MaxRow = i;        }        if(MaxRow != k)        {            for(j = k; j < Var+1; ++j)                swap(A[k][j],A[MaxRow][j]);        }        if(A[k][col] == 0)        {            k--;            FreeOnly[FreeXNum++] = col;            continue;        }        for(i = k+1; i < Equ; ++i)        {            if(A[i][col])            {                Lcm = LCM(abs(A[i][col]),abs(A[k][col]));                ta = Lcm / abs(A[i][col]);                tb = Lcm / abs(A[k][col]);                if(A[i][col] * A[k][col] < 0)                    tb = -tb;                for(j = col; j < Var+1; ++j)                    A[i][j] = (A[i][j]*ta%2 - A[k][j]*tb%2 + 2) % 2;            }        }    }    for(i = k; i < Equ; ++i)    {        if(A[i][col])            return -1;    }    if(k < Var)    {//        for(i = k-1; i >= 0; --i)//        {//            FreeXNum = 0;//            for(j = 0; j < Var; ++j)//            {//                if(A[i][j] && FreeX[j])//                {//                    FreeXNum++;//                    FreeIndex = j;//                }//            }//            if(FreeXNum > 1)//                continue;//            temp = A[i][Var]%2;//            for(j = 0; j < Var; ++j)//            {//                if(A[i][j] && j != FreeIndex)//                    temp = (temp - A[i][j]*X[j]%2 + 2) % 2;//            }//            X[FreeIndex] = temp / A[i][FreeIndex] % 2;//            FreeX[FreeIndex] = 0;//        }//        j = 0;//        for(i = 0; i < Var; ++i)//        {//            if(FreeX[i])//                FreeOnly[j++] = i;//        }        return Var - k;    }    for(i = Var-1; i >= 0; --i)    {        temp = A[i][Var] % 2;        for(j = i+1; j < Var; ++j)        {            if(A[i][j])                temp = (temp - A[i][j]*X[j]%2 + 2) % 2;        }        if(temp % A[i][i] != 0)            return -2;        X[i] = temp / A[i][i] % 2;    }    return 0;}int Solve(){    FreeNum = Gauss();    if(FreeNum == -1)        return INF;    else if(FreeNum == 0)    {        int Ans = 0;        for(int i = 0; i < Var; ++i)            Ans += X[i];        return Ans;    }    else    {        int Ans = INF;        for(int i = 0; i < (1 << FreeNum); ++i)        {            int Cnt = 0;            for(int j = 0; j < FreeNum; ++j)            {                if(i & (1<<j))                {                    X[FreeOnly[j]] = 1;                    Cnt++;                }                else                    X[FreeOnly[j]] = 0;            }            for(int j = Var-FreeNum-1; j >= 0; --j)            {                int idx;                for(idx = j; idx < Var; ++idx)                    if(A[j][idx])                        break;                X[idx] = A[j][Var];                for(int k = idx+1; k < Var; ++k)                {                    if(A[j][k])                        X[idx] = (X[idx] - X[k] + 2)%2;                }                Cnt += X[idx];            }            Ans = min(Ans,Cnt);        }        return Ans;    }}void Init(int N){    memset(A,0,sizeof(A));    memset(X,0,sizeof(X));    Equ = Var = N*N;    for(int i = 0; i < N; ++i)    {        for(int j = 0; j < N; ++j)        {            A[i*N+j][i*N+j] = 1;            if(i > 0)                A[(i-1)*N+j][i*N+j] = 1;            if(i < N-1)                A[(i+1)*N+j][i*N+j] = 1;            if(j > 0)                A[i*N+j-1][i*N+j] = 1;            if(j < N-1)                A[i*N+j+1][i*N+j] = 1;        }    }}char s[10][10];int main(){    int N = 4;    for(int i = 0; i < 4; ++i)        scanf("%s",s[i]);    Init(N);    for(int i = 0; i < 4; ++i)    {        for(int j = 0; j < 4; ++j)        {            if(s[i][j] == 'b')                A[i*4+j][16] = 1;            else                A[i*4+j][16] = 0;        }    }    int Ans1 = Solve();    Init(N);    for(int i = 0; i < 4; ++i)    {        for(int j = 0; j < 4; ++j)        {            if(s[i][j] == 'b')                A[i*4+j][16] = 0;            else                A[i*4+j][16] = 1;        }    }    int Ans2 = Solve();    if(Ans1 == INF && Ans2 == INF)        printf("Impossible\n");    else        printf("%d\n",min(Ans1,Ans2));    return 0;}

0 0
原创粉丝点击