金币阵列问题

问题描述:

有m*n(1 ≤ m, n ≤ 100)个金币在桌面上排成一个 m 行 n 列的阵列。每一枚金币或正面朝上或背面朝上。用数字表示金币状态,0表示金币正面朝上,1 表示背面朝上。

金币阵列游戏的规则是:
1. 每次可将任一行金币翻过来放在原来的位置上;
2. 每次可任选 2 列,交换这 2 列金币的位置。
本题要求对于给定的金币阵列初始状态和目标状态,编程计算按金币游戏规则,将金币阵列从初始状态变换到目标状态所需的最少变换次数。

数据输入:

输入的测试数据的第一行是一个不超过 10 的正整数 k,表示有 k 个测试用例. 每个测试用例的第一行是两个正整数 m, n. 接下来是 m 行,每行有 n 个用空白符分隔的 0 或 1. 这 m*n 个 0-1 表示金币的初始状态阵列。最后是 m 行,每行 n 个 用空白符分隔的 0 或 1,表示金币阵列的目标状态。

数据输出:
对于每个测试用例,输出一行包含一个整数,表示按照要求规则将金币阵列从初始状态变换为目标状态所需要的最少变换次数。如果不能按照变换规则将初始状态变换为目标状态(即无解时)则输出 -1。

数据样例:
Sample Input
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
Sample Output
2
-1

C语言代码:

#include "stdio.h"
#include "stdlib.h"
#define size  100
int num; //输入几组数据
int row; //行数
int column; //列数
int count; //交换次数
int min;
int a[size][size]; //初始矩阵
int b[size][size]; //最终矩阵
int c[size][size]; //临时存放矩阵
int found; //初始到最终是否有交换
void trans_row(int x) // 第x行取反
{
   int i;
   for (i = 0;i<column; i++)
       b[x][i] = b[x][i]^1; // 异或取反
   count++;
}
void trans_column(int x, int y) // 交换x和y列
{
   int i;
   int temp;
   for(i = 0; i < row; i++){
      temp=b[i][x];
      b[i][x]=b[i][y];
      b[i][y]=temp;
   }
   if (x != y)
      count++;
}
int is_same(int x, int y) //比较x和y列是否相同
{
   int i;
   for(i = 0; i <row; i++)
       if (a[i][x] != b[i][y])
           return 0;
   return 1;
}
void copy(int a[size][size], int b[size][size]) // 拷贝数组
{
   int i,j;
   for (i = 0; i <row; i++)
      for (j = 0; j < column; j++)
         a[i][j] = b[i][j];
}
int main(){
    int i,j,k,p;
    int exchgmin[size];
    scanf("%d",&num);
    for(i=0;i<num;i++){
       scanf("%d",&row);
       scanf("%d",&column);
       for(j=0;j<row;j++)
         for(k=0;k<column;k++)
           scanf("%d",&a[j][k]);
       for(j=0;j<row;j++)
         for(k=0;k<column;k++)
           scanf("%d",&b[j][k]);
       copy(c,b); //保护原始数组b
       min=row+column+1;
       for(j=0;j<column;j++){
          copy(b,c);  //恢复原始数组b
          count=0;   //交换次数清零
          trans_column(0,j); //把每一列都假设成为第一列的目标状态,穷举这column中情况
          for(k=0;k<row;k++){ //如果行不同,则将行转换
            if(a[k][0]!=b[k][0])
              trans_row(k);
          }
          for(k=0;k<column;k++){//穷举其他所有列,如果相同则交换,说明目标状态统一,否则找不到与该列相同,说明不可行
             found=0;
             for(p=k;p<column;p++){
               if(is_same(k,p)){
                  trans_column(k,p);
                  found=1;
                  break;
               }
             }
             if(!found)
               break;
          }
         if(found&&count<min) //如果可行,找出最小值
              min=count; 
       }
      if(min<row+column+1) //如果交换次数比初始值小,将其保存为当前组的最小交换次数,否则不可实现交换
         exchgmin[i]=min;
      else exchgmin[i]=-1;
    }
    for(i=0;i<num;i++)
      printf("%d/n",exchgmin[i]);
    system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值