首页 > 代码库 > NEFU 506&&ZOJ 3353 Chess Board (四种构造的高斯消元)

NEFU 506&&ZOJ 3353 Chess Board (四种构造的高斯消元)

题目链接

题意:有四种翻转方式,问是否能使得所有棋子都变为0,求最小步数。

题解:依次构造枚举求出最小值即可。

 

#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <queue>#include <vector>#include <map>#include <ctime>using namespace std;const int inf=0x3f3f3f;const int maxn=300;//有equ个方程,var个变元。增广矩阵行数为equ,列数为var+1,分别为0到varint equ,var;int a[maxn][maxn]; //增广矩阵int x[maxn]; //解集int free_x[maxn];//用来存储自由变元(多解枚举自由变元可以使用)int free_num;//自由变元的个数//返回值为-1表示无解,为0是唯一解,否则返回自由变元个数int gauss(){    int max_r,col,k;    free_num=0;    for(k=0,col=0; k<equ&&col<var; k++,col++)    {        max_r=k;        for(int i=k+1; i<equ; i++)            if(abs(a[i][col])>abs(a[max_r][col]))                max_r=i;        if(!a[max_r][col])        {            k--;            free_x[free_num++]=col;            continue;        }        if(max_r!=k)            for(int j=col; j<var+1; j++)                swap(a[k][j],a[max_r][j]);        for(int i=k+1; i<equ; i++)        {            if(a[i][col])            {                for(int j=col; j<var+1; j++)                    a[i][j]^=a[k][j];            }        }    }    for(int i=k; i<equ; i++)        if(a[i][col])            return -1;    if(k<var) return var-k;    for(int i=var-1; i>=0; i--)    {        x[i]=a[i][var];        for(int j=i+1; j<var; j++)            x[i]^=(a[i][j]&&x[j]);    }    return 0;}int n,m;//注意一定要分清左下和右上!!!void init1(){    memset(a,0,sizeof(a));    memset(x,0,sizeof(x));    equ=n*m;    var=n*m;    for(int i=0; i<n; i++)        for(int j=0; j<m; j++)        {            int t=i*m+j;            a[t][t]=1;            if(i>0) a[(i-1)*m+j][t]=1; //            if(i<(n-1)) a[(i+1)*m+j][t]=1; //            if(j>0) a[i*m+j-1][t]=1; //            if(j<(m-1)) a[i*m+j+1][t]=1; //        }}void init2(){    memset(a,0,sizeof(a));    memset(x,0,sizeof(x));    equ=n*m;    var=n*m;    for(int i=0; i<n; i++)        for(int j=0; j<m; j++)        {            int t=i*m+j;            a[t][t]=1;            if(i>0) a[(i-1)*m+j][t]=1; ////if(i<n-1) a[(i+1)*m+j][t]=1; //            if(j>0) a[i*m+j-1][t]=1; //            if(j<(m-1)) a[i*m+j+1][t]=1; //            if(i>0&&j>0) a[(i-1)*m+j-1][t]=1; //左上            //if(i>0&&j<(m-1)) a[(i-1)*m+j+1][t]=1; //右上            if(i<n-1&&j>0) a[(i+1)*m+j-1][t]=1; //左下            //if(i<n-1&&j<m-1) a[(i+1)*m+j+1][t]=1; //右下        }}void init3(){    memset(a,0,sizeof(a));    memset(x,0,sizeof(x));    equ=n*m;    var=n*m;    for(int i=0; i<n; i++)        for(int j=0; j<m; j++)        {            int t=i*m+j;            a[t][t]=1;            if(i>0) a[(i-1)*m+j][t]=1; //            if(i<(n-1)) a[(i+1)*m+j][t]=1; //            if(j>0) a[i*m+j-1][t]=1; //            if(j<(m-1)) a[i*m+j+1][t]=1; ////if(i>0&&j>0) a[(i-1)*m+j-1][t]=1; //左上            if(i>0&&j<m-1) a[(i-1)*m+j+1][t]=1; //右上            //if(i<(n-1)&&j>0) a[(i+1)*m+j-1][t]=1; //左下            //if(i<n-1&&j<m-1) a[(i+1)*m+j+1][t]=1; //右下        }}void init4(){    memset(a,0,sizeof(a));    memset(x,0,sizeof(x));    equ=n*m;    var=n*m;    for(int i=0; i<n; i++)        for(int j=0; j<m; j++)        {            int t=i*m+j;            a[t][t]=1;            if(i>0) a[(i-1)*m+j][t]=1; //            if(i<(n-1)) a[(i+1)*m+j][t]=1; //            if(j>0) a[i*m+j-1][t]=1; ////if(j<m-1) a[i*m+j+1][t]=1; ////if(i>0&&j>0) a[(i-1)*m+j-1][t]=1; //左上            if(i>0&&j<m-1) a[(i-1)*m+j+1][t]=1; //右上            //if(i<(n-1)&&j>0) a[(i+1)*m+j-1][t]=1; //左下            if(i<(n-1)&&j<(m-1)) a[(i+1)*m+j+1][t]=1; //右下        }}int solve(){    int t=gauss();    if(t==-1)    {        return inf;    }    else if(t==0)    {        int ans=0;        for(int i=0; i<n*m; i++)            ans+=x[i];        return ans;    }    else    {        //枚举自由变元        int ans=0x3f3f3f3f;        int tot=(1<<t);        for(int i=0; i<tot; i++)        {            int cnt=0;            for(int j=0; j<t; j++)            {                if(i&(1<<j)) //注意不是&&                {                    x[free_x[j]]=1;                    cnt++;                }                else x[free_x[j]]=0;            }            for(int j=var-t-1; j>=0; j--)            {                int idx;                for(idx=j; idx<var; idx++)                    if(a[j][idx])                        break;                x[idx]=a[j][var];                for(int l=idx+1; l<var; l++)                    if(a[j][l])                        x[idx]^=x[l];                cnt+=x[idx];            }            ans=min(ans,cnt);        }        return ans;    }}char data[30][30];int main(){    while(scanf("%d%d",&n,&m)&&n&&m)    {        //getchar();        for(int i=0; i<n; i++)            cin>>data[i];        init1();        for(int i=0; i<n; i++)            for(int j=0; j<m; j++)                if(data[i][j]==1) a[i*m+j][n*m]=1;        int ans1=solve();        init2();        for(int i=0; i<n; i++)            for(int j=0; j<m; j++)                if(data[i][j]==1) a[i*m+j][n*m]=1;        int ans2=solve();        init3();        for(int i=0; i<n; i++)            for(int j=0; j<m; j++)                if(data[i][j]==1) a[i*m+j][n*m]=1;        int ans3=solve();        init4();        for(int i=0; i<n; i++)            for(int j=0; j<m; j++)                if(data[i][j]==1) a[i*m+j][n*m]=1;        int ans4=solve();        int ans=min(min(ans1,ans2),min(ans3,ans4));        if(ans==inf) puts("Impossible");        else        {            if(ans==ans1) printf("1 %d\n",ans);            else if(ans==ans2) printf("2 %d\n",ans);            else if(ans==ans3) printf("3 %d\n",ans);            else if(ans==ans4) printf("4 %d\n",ans);        }    }    return 0;}

 

NEFU 506&&ZOJ 3353 Chess Board (四种构造的高斯消元)