金币阵列问题

问题描述:ios

有m x n (m<=100, n<=100 ) 个金币在桌面上排成一个m行n 列的金币阵列。每一枚金币或正面朝上或背面朝上。用数字表示金币状态,0表示金币正面朝上,1 表示背面朝上。金币阵列游戏的规则是:
(1)每次可将任一行金币翻过来放在原来的位置上;
(2)每次可任选2 列,交换这2 列金币的位置。

算法设计:
算法

        给定金币阵列的初始状态和目标状态,计算按金币游戏规则,将金币阵列从初始状态变换到目标状态所需的最少变换次数。ide


数据输入:
        由文件input.txt给出输入数据。文件中有多组数据。文件的第1行有1 个正整数k,表示有k 组数据。每组数据的第1 行有2 个正整数m 和n。如下的m行是金币阵列的初始状态,每行有n 个数字表示该行金币的状态,0 表示金币正面朝上,1 表示背面朝上。接着的m行是金币阵列的目标状态。

结果输出:
spa

        将计算出的最少变换次数按照输入数据的次序输出到文件output.txt。相应数据无解时输出-1。
输入文件示例 输出文件示例
input.txt 
2
4 3
1 0 1
0 0 0
1 1 0
1 0 1

1 0 1
1 1 1
0 1 1
设计

1 0 1orm


4 3
1 0 1
0 0 0
1 0 0
1 1 1

1 1 0
1 1 1
0 1 1
1 0 1
游戏


output.txt
2
ci

-1input


2015年9月21日:it

#include<malloc.h>
#include<iostream>
#include<fstream>


#define INF 1<<30


using namespace std;
/*将矩阵a的第col行进行行变换*/
void transfer_row(int array[],int n)
{
    int i=0;
    for(i=0;i<n;i++)
        array[i]^=1;
}

/*交换矩阵a的i和j列*/
void swap_columns(int **a,int m,int n,int i,int j)
{
    int k=0;
    while(k<m)
    {
        int tmp=a[k][i];
        a[k][i]=a[k][j];
        a[k][j]=tmp;
        k++;
    }
}

/*比较矩阵a的第col_a列和矩阵b的第col_b列是否相等*/
int compare_column(int **a,int **b,int m,int n,int col_a,int col_b)
{
    int k=0;
    for(k=0;k<m;k++)
    {
        if(a[k][col_a]!=b[k][col_b])
        return 0;
    }
    return 1;
}

/*将矩阵src的内容复制到矩阵dest中*/
void copy_array(int** dest,int **src,int m,int n )
{
    for(int i=0;i<m;i++)
        for(int j=0;j<n;j++)
            dest[i][j]=src[i][j];
}


/**寻找将原始矩阵a变换到目标矩阵b的最少变换次数,若是不能将a变换到b,那么返回-1*/
int find(int **a,int **b,int m,int n)
{
    /**flag记录一次变换,是否可以达到目标矩阵*/
    int flag=0;

    /**best为最少交换次数,初始值为无穷大*/
    int best=INF;

    /**count记录一次变换过程当中须要进行交换的次数*/
    int count=0;

    int **tmp=(int **)malloc(sizeof(int *)*m);
    int i=0;
    for(i=0;i<m;i++)
        tmp[i]=(int *)malloc(sizeof(int)*n);
    
    copy_array(tmp,a,m,n);


    /*以列变换为基准,一次将初始矩阵a的每一列与第一列交换*/
    for(i=0;i<n;i++)
    {
        swap_columns(a,m,n,i,0);
        if(i!=0)
            count++;
        //int j=0;
        /*列变换后,将a的新的第一列和目标矩阵b的第一列比较,
        若a中第一列中某行元素与b中第一列相应行的元素不相等,则将a中该行进行变换
        完成此过程后,a的第一列元素和b的第一列元素彻底相同,下面列变换过程当中就不能再进行行变换!
        */
        for(int j=0;j<m;j++)
        {
            if(a[j][0]!=b[j][0])
            {
                transfer_row(a[j],n);
                count++;
            } 
        }

        //int k=0;
        /**从a中一次寻找相应的某些列使得这些列一次和b中的第2到第n列相等,
        若是查找成功,则说明此种变换能够达到目标状态,而后将此种变换所花费的变换次数和当前最有变换次数best比较
        若是小于best,则将best更新此种变换的花费的变换次数
        */
        for(int j=1;j<n;j++)
        {
            flag=0;
            for(int k=j;k<n;k++)
            {
                if(compare_column(a,b,m,n,k,j))  // 比较a的第k列和b的第j列是否相等
                {
                    if(k!=j)
                    { 
                        count++;
                        swap_columns(a,m,n,k,j); // 若是a与目标状态b的相同列的位置不同就对a进行列变换
                    } 
                    flag=1;         // 每次若是a中有与b这一列相同的列就直接置flag为1而后跳出循环
                    break;
                }
            }
            if(flag==0)
                break;
            //count=0;
        }
        if(flag==1&&best>count)
            best=count;
        count=0;
        copy_array(a,tmp,m,n);
    }
    if(best<INF)
        return best;
    else
        return -1;
}


int main()
{
    ifstream in("input.txt");
    int m,n;
    cin>>m>>n;
    int **a=(int **)malloc(sizeof(int*)*m);
    int **b=(int **)malloc(sizeof(int*)*m);
    for(int i=0;i<m;i++)
    {
        a[i]=(int *)malloc(sizeof(int)*n);
        b[i]=(int *)malloc(sizeof(int)*n);
    }

    for(int i=0;i<m;i++)
        for(int j=0;j<n;j++)
            cin>>a[i][j];
    for(int i=0;i<m;i++)
        for(int j=0;j<n;j++)
            cin>>b[i][j];

    int res=find(a,b,m,n);
    cout<<res<<endl;
}