结论
自己想的,但应该没有问题。
先说结论,在判断是否要对(i, j)位置的把手进行切换时,只需要计算一下第i行和第j列总共7个把手(以下称为(i, j)对应的十字)中闭合的把手数目,如果是奇数个就进行切换,偶数个就不进行切换。(奇数个是该位置的把手进行过切换的充要条件)
因此我们从上到下从左到右顺次的对16个把手进行上述判断。如果判断结果是奇数个那么说明该位置被切换过,进行记录即可。可以在O(16 * 7)的时间复杂度给出结果。
证明
这里只提供证明的思路
1. 先证明:如果(i, j)位置的把手被切换过,其对应十字的所有7个把手中闭合的把手数目一直都将是奇数个。(切换过->奇数个)
- 因为先后切换的顺序不影响最后的状态,倘若我们要证明(i, j)对应十字有奇数个闭合的把手,我们只需要把(i, j)看成是第一次切换的即可。
- 因为一开始所有把手都是打开的。那么此时对(i, j)进行切换,其对应的7个把手中有7个都变成闭合,是奇数个(初始状态是奇数个)。
- 假设后来在(x, y)的位置((x, y)与(i, j)不重合)又进行了把手切换
a)如果(x, y)在第i行(或者第j列),那么这次切换将会改变第i行(或第j列)上所有的把手状态。第i行中如有a个闭合则切换后有4 - a个闭合(a取0,1,2,3,4)。不管a的取值是多少从a变成4 - a不改变奇偶性,(i, j)对应的7个把手中闭合的把手数仍然是奇数个。
b)如果(x, y)不在第i行也不在第j列,那么这次切换将会改变(i, y)和(x, j)2个位置的把手的状态,这2个把手的状态是(0, 0)或(0, 1)或(1, 0)或(1, 1).无论是哪种情况,在进行切换之后奇偶性依然是没有改变的。这7个把手中仍然是奇数个把手闭合。
2. 再证明如果是奇数个,那么一定是被切换过。(奇数个->切换过)
这个可能不好证,但是如果我们证明了没有切换的把手对应的十字中闭合的把手一直将是偶数个(没切换->偶数个),那同样可以得出奇数个->切换过。
所以我们转而证明:没切换->偶数个
这个证明思路就和上面的一模一样了。
因此我们说明了对应十字上有奇数个闭合开关是切换过的充要条件。
推广
由上述证明不难发现,此法可推广至边长为偶数的正方形或者长和宽均为偶数的长方形。
边长为奇数的正方形会由于上述证明中加粗部分失效而不满足此性质。
C++ 代码
#include <iostream>
#include <vector>
using namespace std;
int a[4][4];
vector<pair<int, int>> res;
bool Ispush(int x, int y)
{
int tmp = 0;
for(int i = 0; i < 4; ++ i)
if(a[x][i]) ++ tmp;
for(int i = 0; i < 4; ++ i)
if(a[i][y]) ++ tmp;
if(a[x][y]) -- tmp;
return tmp & 1;//如果是奇数个1返回true
}
int main()
{
for(int i = 0; i < 4; ++ i)
for(int j = 0; j < 4; ++ j)
{
char c;
scanf(" %c", &c);
a[i][j] = (c == '+' ? 1 : 0);
}
for(int i = 0; i < 4; ++ i)
for(int j = 0; j < 4; ++ j)
if(Ispush(i, j))//如果是奇数个1则要改变这个位置的状态
res.emplace_back(pair<int, int>{i + 1, j + 1});
printf("%d\n", res.size());
for(auto &item : res) printf("%d %d\n", item.first, item.second);
return 0;
}
太强了,原先以为我的二进制已经够快了(272ms),没想到还可以更快,阁下的代码仅需67ms,实在是太强啦,阁下的分析能力实在是令吾钦佩,我什么时候也可以怎么强呢?
牛逼
这道题,至少测试数据的棋盘中是最优解的同时也是唯一解(不考虑一个开关按多次的情况,因为无意义),但我没办法在数学证明所有情况下成立。
切换某个把手只会改变该把手对应十字的奇偶性,对其他十字无影响,所以在每个把手至多切换一次的情况下,只存在一个解法,就是把所有奇数把手切换掉
佬能说明一下为什么所有奇数把手都切换掉的情况一定是全0状态吗,感觉不会有其他状态,但是不知道该怎么证明
首先全0状态显然所有十字都是偶数,然后因为操作一个把手只改变他对应十字的奇偶,所以如果想某个把手对应的十字变成偶数,就需要对该把手操作偶数次,这等价于没有操作。那么所有十字都为偶数只有全0这一种情况,所以切换掉所有奇数十字后肯定会变为全0状态
这道题所有情况一定都有解吗?也就是能否有人证明一下全都为0的情况是唯一的所有十字(每7个格子)都为偶数的情况
按照这个思路的话,每行每列都多算了;
只需要求出每行和每列的1总数,对于x,y,求行x+列y-a[x][y]就可以了;
如果用bitset,可以再降;
太强了
没明白,太抽象了
orz
orz,我和大佬做法一样
你也是佬,orz
好强!!!
orz
神了
怎么证明这种按法一定是最小步骤呢
因为他证明的就是充要条件
这个厉害!
O(16*7)不就是O(1)吗?
这道题是,改四为N的话就是O(n^3);
改成n的话这个方法就不一定有用了,如果行列不是4的而是奇数的话奇偶性就变了