金币阵列问题

问题描述: 有mxn(m<=100,n<=100)枚金币在桌面上排成一个m行n列的金币阵列。每一枚金币或正面朝上,或背面朝上。用数字表示金币状态,0表示正面朝上,1表示金币背面朝上。

       金币游戏的规则是:(1)每次可将任一行金币翻过来放在原来的位置上(2)每次可任选2列,变换着2列金币的位置

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

        分析:由于规则(2) 对(1) 有约束,故进行(2) 操作后不能进行(1)操作,基于此,可设计以下方案:

        对原始阵列(A)1~n分别作为第1列进行行变换(A'),使之与目标列相匹配(同时统计变换次数),然后从第二列起目标列依次与A'相匹配, 同时进行列变换(统计变换次数),若不能找到即输出"-1",否则更新变换次数,最终输出可能的最小变换次数,最坏时间复杂度O(n^3*m)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define oo 0x3f3f3f3f//1061109567

void Swap_Column(char **temp,int m,int j1,int j2){
	int i;
	for(i = 0 ; i < m ; i ++)
		if(temp[i][j1] != temp[i][j2]){
			if(temp[i][j1] == '0'){
				temp[i][j1] = '1';
				temp[i][j2] = '0';
			}
			else{
				temp[i][j1] = '0';
				temp[i][j2] = '1';
			}
		}
}

void Row_Change(char **temp,int i,int n){
	int j;
	for(j = 0 ; j < n ; j ++){
		temp[i][j] = (temp[i][j] == '0') ? '1':'0';
	}
}

int Is_Same(char **goal_matrix,char **temp,int k,int r,int m){
	int i;
	for(i = 0 ; i < m ; i ++){
		if(goal_matrix[i][k] != temp[i][r])
			break;
	}
	if(i == m) return 1;
	return 0;
}

void Copy(char **temp,char **init_matrix,int m){
	int i;
	for(i = 0 ; i < m ; i ++)
			strcpy(temp[i],init_matrix[i]);
}

void Judge_And_Count(char **init_matrix,char **goal_matrix,int m,int n){
	int i,j,k,r,count,flag,count1 = 0,least_num = oo; 
	char **temp = (char **)malloc(sizeof(char*)*m);
	for(i = 0;i < m;i ++){ 
		temp[i] = (char *)malloc(sizeof(char)*(n+1));
		strcpy(temp[i],init_matrix[i]);
	} 
	for(j = 0; j < n ; j ++){
		count = 0;
		flag = 1; //当前变换存在标志 
		if(j > 0) {
			Swap_Column(temp,m,0,j);
			count ++;
		}
		for(i = 0 ;i < m ; i ++)//行匹配
			if(temp[i][0] != goal_matrix[i][0]){
				Row_Change(temp,i,n);
				count ++;
			}
		for(k = 1; k < n ; k ++){//列匹配 
			for(r = k ; r < n ; r ++){
				if(Is_Same(goal_matrix,temp,k,r,m)){ 
					if(k != r){//k!=r,否则会多统计一次变换 
						Swap_Column(temp,m,k,r);
					 	count ++;
					}
					break;
				}
			}
			if(r == n){
				count1 ++; //count1:整个阵列是否存在变换 
				flag = 0;
				break;
			}
		}
		if(flag && least_num > count)
			least_num = count;
		Copy(temp,init_matrix,m); //复原temp 
	}
	printf("%d\n",count1 == n ? -1 : least_num);
}

int main(){
	int m,n,i;
	char **init_matrix,**goal_matrix;
	while(scanf("%d%d",&m,&n) != EOF){
		getchar();
		//二维数组的动态开辟 
		init_matrix = (char **)malloc(sizeof(char*)*m);
		goal_matrix = (char **)malloc(sizeof(char*)*m);
		for(i = 0;i < m;i ++){
			init_matrix[i] = (char *)malloc(sizeof(char)*(n+1));
			goal_matrix[i] = (char *)malloc(sizeof(char)*(n+1));
		}
		for(i = 0; i < m;i ++)
			scanf("%s",init_matrix[i]);
		for(i = 0; i < m;i ++)
			scanf("%s",goal_matrix[i]);
		Judge_And_Count(init_matrix,goal_matrix,m,n);
	}
	return 0;
}
测试样例:

4 3
101
000
110
101
101
111
011
101---->2
4 3
101
000
100
111
110
111
011
101--->-1
[参考]:http://blog.csdn.net/softwareldu/article/details/10509999

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值