zoukankan      html  css  js  c++  java
  • 【算法课】金币阵列问题

    金币阵列问题

    【题意】

    给出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
    ",Col,cnt);
    110             Ans = cnt ;
    111         }
    112     }
    113     if( Ans != inf )
    114         printf("%d
    ",Ans);
    115     else{
    116         printf("-1
    ");
    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
  • 相关阅读:
    floating IP 原理分析
    创建 floating IP
    Why Namespace?
    虚拟 ​router 原理分析- 每天5分钟玩转 OpenStack(101)
    链接脚本使用一例2---将二进制文件 如图片、MP3音乐、词典一类的东西作为目标文件中的一个段
    linux-2.6.26内核中ARM中断实现详解(转)
    有关Cache –(1) linux list之中的Prefetc
    Linux 内核中的 GCC 特性
    对entry-common.S和call.S的部分理解1
    kernel&uboot学习笔记
  • 原文地址:https://www.cnblogs.com/Osea/p/11515051.html
Copyright © 2011-2022 走看看