问题描述:有m*n(m小于等于100,n小于等于100)枚金币在桌面上排成一个m行n列的金币阵列。每一枚金币或正面朝上,或背面朝上。用数字代表金币状态,0表示金币正面朝上,1表示金币背面朝上。
金币阵列游戏的规则是:(1)每次可将任一行金币翻过来放在原来的位置上;(2)每次可任选2列,交换这2列金币的位置。
算法设计:给定金币阵列的初始状态和目标状态,计算按金币游戏规则,将金币阵列从初始状态变换到目标状态所需的最少变换次数。
思路:根据金币阵列的游戏规则,可以先进行行变换,也可以先进行列变化,但是行变换容易变乱,这里考虑列变换优先。
先固定某一列,与目标列进行比较,如果这一列中有不相同的元素,进行行变换,以后不再进行行变换,只进行列变换。
【代码】
#include<stdio.h>
#include<malloc.h>
int count;
int **temparr;
int **b;
void tranrow(int j)
{//行变换
for(int i=0;i<3;i++)
temparr[j][i]=1-temparr[j][i];
count++;
}
void trancol(int i,int j)
{//列变换
int temp;
for(int k=0;k<4;k++){
temp=temparr[k][i];
temparr[k][i]=temparr[k][j];
temparr[k][j]=temp;
}
if(i!=j)
count++;
}
int same(int j,int i,int m,int n)
{
int k;
for(k=0;k<m;k++)
{
if(temparr[k][i]!=b[k][j])
return 0;
}
return 1;
}
int main()
{
int num;
int s;
int m,n;//m行数,n列数
printf("请输入有几组数据:");
scanf("%d",&num);
int answer[20];
for(s=0;s<20;s++)
answer[s]=99999;
for(s=0;s<num;s++){
printf("请输入矩阵的行数和列数:");
scanf("%d%d",&m,&n);
int **a;
int i,j,k;
a=(int **)malloc(sizeof(int*)*m);
for(i=0;i<m;i++)
a[i]=(int *)malloc(sizeof(int)*n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf("%d",&a[i][j]);
b=(int **)malloc(sizeof(int*)*m);
for(i=0;i<m;i++)
b[i]=(int *)malloc(sizeof(int)*n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf("%d",&b[i][j]);
temparr=(int **)malloc(sizeof(int*)*m);
for(i=0;i<m;i++)
temparr[i]=(int *)malloc(sizeof(int)*n);
for(k=0;k<n;k++)
{
for(i=0;i<m;i++)
for(j=0;j<n;j++)
temparr[i][j]=a[i][j];
count=0;
trancol(0,k);
for(i=0;i<m;i++)
{
if(temparr[i][0]!=b[i][0])
tranrow(i);
}
int flag;
for(i=0;i<n;i++)
{
flag=0;
if(same(i,i,m,n))
{
flag=1;
continue;
}
for(j=i+1;j<n;j++)
{
if(same(i,j,m,n))
{
trancol(i,j);
flag=1;
break;
}
}
if(flag==0)
break;
}
if(flag==1)
answer[s]=count;
}
}
for(s=0;s<num;s++){
if(answer[s]<99999)
printf("次数:%d\n",answer[s]);
else
printf("次数为-1\n");
}
return 0;
}