【算法课】金币阵列问题

金币阵列问题

【题意】

给出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 */

原文地址:https://www.cnblogs.com/Osea/p/11515051.html

时间: 2024-11-13 04:45:15

【算法课】金币阵列问题的相关文章

Construct Binary Tree from Inorder and Postorder Traversal (算法课上的题)

Construct Binary Tree from Inorder and Postorder Traversal 这道题之前算法课上好像遇到过,思路也很简单的. 思路:后序序列的最后一个元素就是树根,然后在中序序列中找到这个元素(由于题目保证没有相同的元素,因此可以唯一找到),中序序列中这个元素的左边就是左子树的中序,右边就是右子树的中序,然后根据刚才中序序列中左右子树的元素个数可以在后序序列中找到左右子树的后序序列,然后递归的求解即可.(在去除了根节点之后,中序遍历和后序遍历的前N个树都是

算法课笔记系列(六)—— 图(Part2)

上一周去了一趟说走就走的治疗之旅,所以算法课都没能上.:( 不过,人生有过这样一次,很足够.只要永远做自己认为对的事情就不会有跨不过去的坎. 跟上周一样,这一周的内容包含几个小部分,分别为最短路径动态规划.所有点对之间的最短路径和网络流. 第一部分:最短路径动态规划 对于一个有向图G=(V, E), 每一条边权重为cvw(权重可为负), 问题是找到从节点s到t的最短的路径.如果边的权重中有负值,则Dijkstra方法不适用.因此我们想到一个办法,给每一个权值加上一个正常数使得每一条边的权重都为非

[算法课][分治]寻找凸包 (Convex Hull)

凸包问题是算法中经典的题目了,最近算法课讲分治问题时提到了Convex Hull,算法导论的书上也花了篇幅讨论了Convex Hull的求解,主要是Graham方法. 为了能更好地理解分治和Graham这两种解法,我决定自己动手把代码写一遍. 然而,在写之前,我发现我大一学的用行列式求解由三个点围城的三角形面积已经忘得差不多了,现在补充一下: 利用这个计算结果来判断点p3在p1p2直线的左侧还是右侧 下面是分治算法求解: #include <iostream> #include <alg

【1-4】金币阵列问题

问题描述: 有m ′ n(m £ 100,n £ 100) 个金币在桌面上排成一个m 行 n 列的金币阵列.每一枚金 币或正面朝上或背面朝上.用数字表示金币状态,0 表示金币正面朝上,1 表示背面朝上. 金币阵列游戏的规则是: (1)每次可将任一行金币翻过来放在原来的位置上: (2)每次可任选 2 列,交换这 2 列金币的位置. ′编程任务: 给定金币阵列的初始状态和目标状态,编程计算按金币游戏规则,将金币阵列从初始状 态变换到目标状态所需的最少变换次数. ′数据输入: 由文件 input.tx

普林斯顿算法课Part2第二周作业_SeamCarving

作业地址:http://coursera.cs.princeton.edu/algs4/assignments/seamCarving.html 作业难点: 1.如何获取图形的RGB属性? 需要研习下Picture.Color类等,使用getRGB().getRed().getGreen().getBlue()等函数; 2.如何计算从顶端到底部的最低energy曲线(即最短路径)? 使用课上讲的Dijkstra算法求解即可: 3.是否将findHorizontalSeam和findVertica

【免费算法课】硅谷工程师直播面试技巧!

开课时间: 北京时间 2015-8-23 09:30 (周日a.m.) 美西时间 2015-8-22 18:30 (周六) 课程安排:本课程为网络直播课,每节2小时,共9节,第一节免费试听. 报名网址:http://www.jiuzhang.com/course/  适合谁? 应届毕业生,刚毕业一年以内的同学,想接受系统的面试算法培训的同学,或想换工作的但是算法比较薄弱的工程师.0基础算法即可参与学习. 课程特色 一流师资,硅谷顶尖IT企业工程师在线授课 讲师段誉老师,算法教学经验近10年,就

普林斯顿大学算法课 Algorithm Part I Week 3 排序稳定性 Stability

稳定性(Stability):先按性质A排序,再按性质B排序,性质B相同的那些项是否仍然是按性质A排序的? 一个稳定的排序,相同值的元素应仍保持相对顺序(relative order) 稳定的算法:插入排序.Mergesort等 不稳定的算法:选择排序:Shellsort等

普林斯顿大学算法课 Algorithm Part I Week 3 排序算法复杂度 Sorting Complexity

计算复杂度(Computational complexity):用于研究解决特定问题X的算法效率的框架 计算模型(Model of computation):可允许的操作(Allowable operations) 成本模型(Cost model):操作数(Operation counts) 上界(Upper bound):最多的成本 下界(Lower bound):最少的成本 最优算法(Optimal algorithm):最有可能性的成本的算法(Algorithm with best pos

算法课作业之删数问题

问题描述: 通过键盘输入一个高精度的正整数n(n的有效位数≤240),去掉其中任意s个数字后,剩下的数字按原左右次序将组成一个新的正整数.编程对给定的n和s,寻找一种方案,使得剩下的数字组成的新数最小. 问题分析: 这个问题是最优子结构问题,即局部最优能决定全局最优解,可以使用贪心算法进行解决.n个正整数去掉s个数字,求使得到的新的正整数最大的删除方案可以等价为:对于n个正整数组成的数字,一个一个地依次去掉s个数字,要求每删除一个数时,都使删除后的新的正整数最小.因此问题转化为求解删除一个数字时