算法设计与实验题解例题:金币阵列问题
问题描述:
有mxn(m <= 100,n <= 100)个金币在桌面上排成一个m行n 列的金币阵列。每一枚金
币或正面朝上或背面朝上。用数字表示金币状态,0表示金币正面朝上,1 表示背面朝上。
金币阵列游戏的规则是:
(1)每次可将任一行金币翻过来放在原来的位置上;
(2)每次可任选2 列,交换这2 列金币的位置。
算法设计:
给定金币阵列的初始状态和目标状态,计算按金币游戏规则,将金币阵列从初始状态变
换到目标状态所需的最少变换次数。
数据输入:
文件中有多组数据。文件的第1行有1 个正整数k,表示有k 组数据。每组数据的第1 行有2 个正整数m 和n。
以下的m行是金币阵列的初始状态,每行有n 个数字表示该行金币的状态,0 表示金币正面朝上,1 表示背面朝上。
接着的m行是金币阵列的目标状态。
«结果输出:
相应数据无解时输出-1。
输入文件示例
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 1
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
输入文件示例
2
-1
代码如下:
//最大变换次数不超过m+n
#include <stdio.h>
#include <stdlib.h>
#define swap(a,b) ((a=a+b),(b=a-b),(a=a-b))
int table1[100][100],table2[100][100],temp[100][100],m,n,ans;//table1为初始状态,table2为目标状态
void cpy(int a[100][100],int b[100][100])//将数组b赋给数组a
{
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
a[i][j]=b[i][j];
}
void change1(int i)//将table1中第i行翻转
{
for(int j=0;j<n;j++)
table1[i][j]^=1;
ans++;
}
void change2(int i,int j)//将table1中第i列与第j列对调
{
if(i!=j)
{
for(int k=0;k<m;k++)
{
swap(table1[k][i],table1[k][j]);
}
ans++;
}
}
bool same(int i,int j)//比较table2中第i列与table1中第j列是否相等
{
for(int k=0;k<m;k++)
if(table2[k][i]!=table1[k][j])
return false;
return true;
}
int main()
{
int t,i,j,k,best;
bool flag;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&m,&n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf("%d",&table1[i][j]);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf("%d",&table2[i][j]);
best=m+n+1;
cpy(temp,table1);//保存初始状态
for(i=0;i<n;i++) //枚举初始状态每一列变换为目标状态第一列的情况
{
ans=0;
change2(0,i);
for(j=0;j<m;j++)
if(table1[j][0]!=table2[j][0])//若此行第一列与目标第一列值不相同,则变换该行
change1(j);
for(j=1;j<n;j++) //在table1中查找与table2中第j列相等的列
{
flag=false; //标记是否找到
for(k=j;k<n;k++)
if(same(j,k))
{
change2(j,k);
flag=true;
break;
}
if(flag==false)
break;
}
if(flag && ans<best)
best=ans;
cpy(table1,temp);
}
if(best<m+n+1)
printf("%d\n",best);
else
printf("-1\n");
}
return 0;
}
posted on 2012-09-07 16:09
大大木马 阅读(999)
评论(0) 编辑 收藏 引用