【算法课】金币阵列问题

金币阵列问题

【题意】

给出01矩阵,请问是否能通过两个操作使得 原01矩阵变换到目标的01矩阵

操作1:行变换 —— 01翻转

操作2:列变换 —— 交换两列

 

【考察】

模拟题

 

【题解】

按顺序模拟即可,

第一步:必须找到某一列作为第一列,通过 0 次或多次的行变换变成与目标矩阵的第一列一样。

第二步:通过交换列,得到与目标矩阵一样的。

注意贪心交换无法达到最小步数

 


 

 

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3  
  4 const int N = 2e2+10;
  5 const int inf = 0x3f3f3f3f;
  6  
  7 //  原数组  source   目标数组  Aim  操作数组
  8 int Src[N][N] , Aim[N][N] , tmp[N][N] ;
  9 int n , m , cnt , Ans ;
 10  
 11 //判断操作数组的某一列 是否和 目标数组当前列 相符
 12 bool SameCol( int C1 , int C2 ){
 13  
 14     for( int i = 1 ; i <= n ; i ++ ){
 15         if( tmp[i][C1] != Aim[i][C2] )
 16             return false ;
 17     }
 18     return true;
 19 }
 20  
 21 //操作1:  对操作数组 某一行金币进行翻转
 22 void Filp( int Row ){
 23     for( int j = 1 ; j <= m ; j++ ){
 24         tmp[Row][j] ^= 1 ;
 25     }
 26     cnt ++ ;
 27 }
 28  
 29 //操作2:  对操作数组 某两列进行交换
 30 void SwapCol( int C1 , int C2 ){
 31  
 32     if( C1 == C2 ) return ; //如果 两列相同则不作处理
 33  
 34     for( int i = 1 ; i <= n ; i++ ){
 35         swap( tmp[i][C1] , tmp[i][C2] );
 36     }
 37     cnt ++ ;
 38 }
 39  
 40 void Input(){
 41  
 42     scanf("%d%d",&n,&m);
 43  
 44     for( int i = 1 ; i <= n ; i++ ){
 45         for( int j = 1 ; j <= m ; j++ ){
 46             scanf("%d",&Src[i][j] );
 47         }
 48     }
 49  
 50     for( int i = 1 ; i <= n ; i++ ){
 51         for( int j = 1 ; j <= m ; j++ ){
 52             scanf("%d",&Aim[i][j] );
 53         }
 54     }
 55  
 56 }
 57  
 58 void Solve(){
 59  
 60     Ans = inf ;
 61  
 62     //选取某一列作为第一列
 63     for( int Col = 1 ; Col <= m ; Col ++ ){
 64  
 65         //操作前应把过程更新的 cnt,tmp[][] 初始化
 66         cnt = 0 ;
 67         memcpy( tmp , Src , sizeof Src ) ;
 68  
 69         //把对应行交换作为第一列
 70         SwapCol( Col , 1 );
 71  
 72         //如果当前位置不符合,则使用“操作1-翻转硬币”使得符合.
 73         for( int i = 1 ; i <= n ; i ++ ){
 74             if( tmp[i][1] != Aim[i][1] )
 75                 Filp(i) ;
 76         }
 77  
 78         //以后不能再用“操作1-翻转硬币”,因为固定了第一列,
 79         //如果使用一次“操作1-翻转硬币”,就会破坏当前第一列
 80  
 81         //***剩下来的任务***:通过交换两列,使得剩下来的都符合Aim
 82  
 83         bool Successful_Col ;
 84         //外循环枚举Aim数组的列位置
 85         for( int k = 2 ; k <= m ; k ++ ){
 86  
 87             Successful_Col = false ;
 88  
 89             //判断当前列是否已经匹配上
 90             if( SameCol( k , k ) ){
 91                 Successful_Col = true ;
 92                 continue ;
 93             }
 94  
 95             //内循环枚举tmp数组列的位置,前k列已经匹配,应从[k+1,m]选择
 96  
 97             for( int j = k+1 ; j <= m ; j ++ ){
 98                 if( SameCol( j , k ) && !SameCol( j , j ) ){
 99                     Successful_Col = true ;
100                     SwapCol( j , k ) ;
101                     break;
102                 }
103             }
104  
105             if( !Successful_Col ) break;
106         }
107  
108         if( Successful_Col && Ans > cnt ){
109             //printf("Col : %d , %d\n",Col,cnt);
110             Ans = cnt ;
111         }
112     }
113     if( Ans != inf )
114         printf("%d\n",Ans);
115     else{
116         printf("-1\n");
117     }
118 }
119 int main(){
120  
121     Input();
122     Solve();
123  
124     return 0;
125 }
126 /*
127 3 6
128  
129 0 0 0 0 0 1
130 0 0 1 1 1 1
131 0 1 0 0 0 0
132  
133 0 0 0 0 0 1
134 0 1 1 1 0 0
135 0 0 0 0 1 0
136  
137 */
View Code

 

posted @ 2019-09-12 20:38  Osea  阅读(726)  评论(0编辑  收藏  举报