小算法系列-反转棋盘
来源:互联网 发布:adobe 编程字体 编辑:程序博客网 时间:2024/04/30 13:14
最后两步结论的得出很不一般啊~ 一开始确实也被题目迷糊蒙了
一个N*M大小的棋盘,每个格子都是0或者1,N和M都是奇数。你每次可以选择反转一行或者一列,被反转的行或列的所有0变成1,所有1变成0。要求使用最少的反转次数,使得每行每列的1的个数是偶数。
输入格式:从键盘输入,第一行是两个正整数N和M,用空格隔开,都不超过20,都是奇数。接下来有N行,每行M个数,都为0或者1,表示棋盘上的数,数字用空格分隔。
输出格式:只有一个数字,表示最少的反转次数。如果不可能通过有限次反转使每行每列的1的个数是偶数,则输出-1。
[输入样例A] 3 3 1 1 1 0 1 1 0 0 1 [输出样例A] 2 | [输入样例B] 5 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 [输出样例B] 3 |
#include <iostream>
using namespace std;
int min(int a, int b)
{
return a < b ? a : b;
}
int main()
{
int N, M;
cin >> N >> M; // 读入N行和M列
int Board[20][20]; // 存储棋盘初始情况
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++)
cin >> Board[i][j];
int Ro = 0; // 有奇数个1的行的数目
for (int i = 0; i < N; i++)
{
int temp = 0; // 用于统计每行的1的个数
for (int j = 0; j < M; j++)
temp += Board[i][j];
Ro += temp % 2; // 如果是奇数则加1
}
int Co = 0; // 有奇数个1的列的数目
for (int j = 0; j < M; j++)
{
int temp = 0; // 用于统计每列的1的个数
for (int i = 0; i < N; i++)
temp += Board[i][j];
Co += temp % 2; // 如果是奇数则加1
}
if (Ro % 2 == 0) // 是偶数
cout << min(Ro + Co, N - Ro + M - Co) << endl;//解释在下面
else
cout << min(Ro + M - Co, N - Ro + Co) << endl;//解释在下面
return 0;
}
乍一看被这个题目吓了一下,没摸清方向,只是觉得转一次行的话,列的又变了,感觉似乎有点复杂。静下心来想想似乎也不是那么复杂了。
仔细分析一下这个题目,如果行反转奇数次的话,则列的奇偶会变化,但是如果反转偶数次的话,则列的奇偶不会变化。并且行反转奇数次的话,那么列的1的奇偶数目会交互,比如列原来有2个奇数列一个偶数列,则行反转1次后,列变为1个奇数列两个偶数列。
因此,如果行的为奇数个1的行数为奇数个的话,则列肯定也是奇数个,不然就没办法达到最终结果。(此过程验证了行和列中1为奇数的数目必须同时为奇数或者同时为偶数)
OK,现在假设N*M的棋盘,行为奇数个1的行数目以及偶数个1的行数目分别为x,y,列的为p,q,显然x + y = N, p + q = M,且如果x为奇数的话,p也为奇数。
1、现在假设我们优先反转行为偶数,则显然我们需要反转x次,如果x为偶数的话,p肯定也为偶数,且反转完之后p和q没有变化,接着需要反转p次列,既总的反转次数为x+p次。而如果x为奇数的话,p肯定也为奇数,且反转完之后,p和q交互了,既反转完后,列的为奇数个1的列数目为偶数,因为M为奇数,p为奇数,则q必然为偶数,则列需要反转q次,总的次数为M-p+x (x + q)
。。。。其他过程同理
先反转奇数
x为奇数时,行优先总反转次数为:M-p+x 列优先总反转次数为:N-x+p
x为偶数是,行优先和列优先一样,总反转次数为:x + p
先反转偶数
x为奇数时,行优先总反转次数为N-x+p,列优先总反转次数为:M - p + x
x为偶数是,行优先和列优先一样,总反转次数为N-x + M-p
得出:
1:行和列里1个数都为偶数时,最少次数为x + p 和 N-x+p 里面较小的那个。
2:行和列里1个数都为奇数时,最少次数为N-x+p 和 M - p + x 里面较小的那一个。
- 小算法系列-反转棋盘
- 棋盘反转
- 算法系列(一):分治策略--棋盘覆盖
- 《反转棋盘》解答
- 算法题练习系列之(十八): 反转链表
- 反转算法
- Sgu棋盘覆盖系列
- 棋盘问题系列
- 小 Q 的棋盘
- 马走日棋盘算法
- 棋盘覆盖算法
- 棋盘覆盖算法
- 马走日棋盘算法
- 棋盘覆盖算法
- 马遍历棋盘算法
- 棋盘覆盖算法
- java 棋盘覆盖算法
- 棋盘划分----分治算法
- grails service
- 动画效果打开层 关闭层
- js表单验证类
- initrd和initramfs
- PHP中常用的数组函数
- 小算法系列-反转棋盘
- 仿51JOB的地区选择效果
- 新手入门:介绍JSP中request属性的用法
- eclipse.ini说明
- 实施经理的工具箱--走出软件作坊:三五个人十来条枪 如何成为开发正规军(七)
- ramdisk与 initrd、initramfs的关系
- SystemVerilog 断言及其应用--(神州龙芯集成)
- Windows2003的LoaderLock
- 新版本浏览器中如何实现图片预览功能