zoj 3353

来源:互联网 发布:ubuntu升级驱动 花屏 编辑:程序博客网 时间:2024/05/16 05:04
Chess Board

Time Limit: 5 Seconds Memory Limit: 65536 KB

There's an N X M board which filled with black and white chesses.

In each move, the player can flip one of these N X M chesses, meanwhile some chesses of its 8 neighbors will switch into its opposite color(from black to white and from white to black).

Here's four change pattern of the flip operation:

1.   .*.     * *   ('*' denotes the position which will change its color, '.' denotes that the color will stay the same.)     .*.   It means the chesses of the choosen position's up, down, left and right will switch its color.           (Don't forgot the chess which the player choose, it'll also switch its color.)2.   **.     * *     *..   It means the chesses of its upper-left, up, left, right and bottom-left will switch its color.3.   .**     * *     .*.   It means the chesses of its up, upper-right, left, right and down will switch its color.4.   .**     * .     .**   It means the chesses of its up, upper-right, left, down and bottom-right will switch its color.

At the beginning, the player should choose one of these four patterns to flip (the player can only use one pattern in a single game), then try to switch the board into allwhite. By the way, we want to find a solution with minimal number of operations, if ties, select the smaller index of pattern.

Input

There are multiple test cases (no more than 150).

The first line of each case contains two integer numbers N and M (1 <=N,M <= 15), indicating the width and the height of the board.

The following N lines containing M characters each describe the initial state of the board. '0' and '1' correspond to white and black, respectively.

Input ends with 0 0.

Output

For each test case output the optimal solution, the pattern should be choosen follows by the minimal number of operations.

If none of these four pattern can switch the board into all white, output "Impossible" for the test case.

Sample Input

1 113 21110115 500000001100111000100000000 0

Sample Output

1 14 13 1
我的代码:
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn=16*16;const int inf=0x3fffffff;int a[maxn][maxn+1],x[maxn],ans;int equ,var,free_num;int n,m;int abs1(int num){    if (num>=0) return num;    else    return -1*num;}void Debug(void){    int i, j;    for (i = 0; i < equ; i++)    {        for (j = 0; j < var + 1; j++)        {            cout << a[i][j] << " ";        }        cout << endl;    }    cout << endl;}inline int gcd(int a, int b){    int t;    while (b != 0)    {        t = b;        b = a % b;        a = t;    }    return a;}inline int lcm(int a, int b){    return a * b / gcd(a, b);}int  dfs(int p)  //枚举自由解,只能取 0-1,枚举完就回带,找到最小的{if (p<=free_num-1) //深入到了主对角线元素非 0 的行了{  //下面就是回带的代码啊  for(int i = free_num-1;i >= 0; --i)        {        int tmp = a[i][var] % 2;        for(int j = i+1;j < var; ++j) //x[i]取决于 x[i+1]--x[var]啊,所以后面的解对前面的解有影响。            if(a[i][j] != 0)                tmp = ( tmp - (a[i][j]*x[j])%2  +  2 ) % 2;        x[i] = (tmp/a[i][i]) % 2; //上面的正常解        } //回带完成了       //计算解元素为 1 的个数;        int sum=0;        for(int i=0;i<var;i++) sum+=x[i];        if (ans>sum) ans=sum;  return 0;}x[p]=0;dfs(p-1);x[p]=1;dfs(p-1);}void swap(int &a,int &b){int temp=a;a=b;b=temp;}int Gauss_1(){    int k,col = 0;  //当前处理的列    for(k = 0;k < equ && col < var;++k,++col)    {        int max_r = k;        for(int i = k+1;i < equ; ++i)            if(a[i][col] > a[max_r][col])                max_r = i;        if(max_r != k)        {            for(int i = k;i < var + 1; ++i)                swap(a[k][i],a[max_r][i]);        }        if(a[k][col] == 0)        {            k--;            continue;        }        for(int i = k+1;i < equ; ++i)        {            if(a[i][col] != 0)            {                int LCM = lcm(a[i][col],a[k][col]);                int ta = LCM/a[i][col], tb = LCM/a[k][col];                if(a[i][col]*a[k][col] < 0)                    tb = -tb;                for(int j = col;j < var + 1; ++j)                    a[i][j] = ( (a[i][j]*ta)%2 - (a[k][j]*tb)%2  +  2 ) % 2;    //a[i][j]只有0和1 两种状态            }        }    }    for(int i = k;i < equ; ++i)        if(a[i][col] != 0)    return -1;   // 无解返回 -1//上述代码是消元的过程,消元完成//Debug();    //唯一解或者无穷解,k<=var    //var-k==0  唯一解;var-k>0 无穷多解,自由解的个数=var-k    //下面这几行很重要,保证秩内每行主元非 0,且按对角线顺序排列        for(int i = 0; i <equ; ++i)//每一行主元素化为非零       if(!a[i][i])       {           int j;           for(j = i+1;j<var;++j)               if(a[i][j])                   break;            if(j == var)                break;            for(int k = 0;k < equ; ++k)                swap(a[k][i],a[k][j]);        }// ----处理保证对角线主元非 0 且顺序,完成    free_num=k;    if (var-k>0) { dfs(var-1); return ans;}    //return -2;    if (var-k==0)//唯一解时,poj1753 本题没唯一解,当题目具体操作给出后,系数矩阵已经固定了!  {      //下面是回带求解,当无穷多解时,最后几行为 0            for(int i = k-1;i >= 0; --i)        {        int tmp = a[i][var] % 2;        for(int j = i+1;j < var; ++j) //x[i]取决于 x[i+1]--x[var]啊,所以后面的解对前面的解有影响。            if(a[i][j] != 0)                tmp = ( tmp - (a[i][j]*x[j])%2  +  2 ) % 2;        //if (a[i][i]==0) x[i]=tmp;   //最后的空行时,即无穷解得        //else        x[i] = (tmp/a[i][i]) % 2; //上面的正常解        }        int sum=0;        for(int i=0;i<var;i++) sum+=x[i];        return sum;  }}char s[20][20];void  init(int id){     memset(a,0,sizeof(a));     memset(x,0,sizeof(x));     for(int i=0;i<var;i++) a[i][var]= (s[i/m][i%m]!='0'),a[i][i]=1;     for(int i=0;i<n;i++)     for(int j=0;j<m;j++)     {         if(id==1)     {             if(i-1>=0) a[(i-1)*m+j][i*m+j]=1;             if(i+1<n) a[(i+1)*m+j][i*m+j]=1;             if(j-1>=0) a[i*m+j-1][i*m+j]=1;             if(j+1<m) a[i*m+j+1][i*m+j]=1;     }     else if(id==2)     {             if(i-1>=0) a[(i-1)*m+j][i*m+j]=1;             if(j-1>=0) a[i*m+j-1][i*m+j]=1;             if(j+1<m) a[i*m+j+1][i*m+j]=1;             if(i-1>=0&&j-1>=0) a[(i-1)*m+j-1][i*m+j]=1;             if(i+1<n&&j-1>=0) a[(i+1)*m+j-1][i*m+j]=1;     }     else if(id==3)     {             if(i-1>=0) a[(i-1)*m+j][i*m+j]=1;             if(i+1<n) a[(i+1)*m+j][i*m+j]=1;             if(j-1>=0) a[i*m+j-1][i*m+j]=1;             if(j+1<m) a[i*m+j+1][i*m+j]=1;             if(i-1>=0&&j+1<m) a[(i-1)*m+j+1][i*m+j]=1;     }     else if(id==4)     {             if(i-1>=0) a[(i-1)*m+j][i*m+j]=1;             if(i+1<n) a[(i+1)*m+j][i*m+j]=1;             if(j-1>=0) a[i*m+j-1][i*m+j]=1;             //if(j+1<m) a[i*m+j+1][i*m+j]=1;             if(i-1>=0&&j+1<m) a[(i-1)*m+j+1][i*m+j]=1;             if(i+1<n&&j+1<m) a[(i+1)*m+j+1][i*m+j]=1;     }     }     return ;}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        if(n==0&&m==0) break;        equ=n*m;var=n*m;        for(int i=0;i<n;i++)        scanf("%s",s[i]);        int minmin=inf;int q;        for(int i=4;i>=1;i--)        {        init(i);        ans=10000000;        int j1=Gauss_1();        if(j1<=minmin&&j1!=-1)        {            minmin=j1;            q=i;        }        }        if(minmin!=inf) printf("%d %d\n",q,minmin);        else printf("Impossible\n");    }    return EXIT_SUCCESS;}


原创粉丝点击