📜  门|门 CS 1996 |第 47 题(1)

📅  最后修改于: 2023-12-03 14:58:34.784000             🧑  作者: Mango

门|门 CS 1996 |第 47 题

这是一道历史悠久的计算机科学竞赛题目,出自于门单元。

题目描述

有一扇铁门,门扇上划分出 $n$ 个小方格,每个小方格上画有一个黑色或白色的点。现在翻转其中若干小方格,使得所有的黑点均在门的上方(不包括上面一排小方格中的点)。请你编写程序判断是否有一种方法可以达到要求

输入格式

第一行两个整数 $n$,$m$,分别表示门扇小方格的数量和需要翻转的方格数。

接下来 $m$ 行,每行两个整数 $x_i$ 和 $y_i$,表示第 $i$ 个需要翻转的小方格的横纵坐标。

输出格式

若可以达到要求,则输出一行 "YES",否则输出一行 "NO"

样例输入
3 2
1 2
2 3
样例输出
YES
思路分析

这是一道非常经典的计算机科学问题,也是习题课和算法竞赛中常常出现的一类问题,称为翻转棋子问题。 首先需要注意的是,如果把一个小方格上的黑点改为白点、白点改为黑点的效果是相同的,因此,如果一个小方格被翻转了奇数次,最终的状态就是黑点,否则就是白点。 另外,题目中给出了一个很重要的限制条件:翻转后所有的黑点均在门的上方,也就是说,翻转不会改变一个小方格上点的状态。 因此,可以使用一个布尔型的数组 $g[i][j]$,表示第 $i$ 行、第 $j$ 列的小方格是否被翻转了。初始状态 $g[i][j]$ 为 false,表示所有的小方格都是白色的。然后依次考虑每一个需要翻转的小方格 $(x_i, y_i)$,将 $g_{x_i,y_i}$ 取反。最后遍历所有的小方格,判断黑点是否都在门的上方即可。

代码实现
def flip(g, x, y):
    g[x][y] = not g[x][y]

n, m = map(int, input().split())
g = [[0] * n for _ in range(n)]
for i in range(m):
    x, y = map(int, input().split())
    flip(g, x-1, y-1)
for j in range(n):
    for i in range(n-1):
        if g[i][j]:  # 当前方格被翻转了
            flip(g, i+1, j)
            flip(g, i, j+1)
if all([not g[n-1][j] for j in range(n)]):
    print("YES")
else:
    print("NO")

以上就是本题的解题思路和代码实现,希望能对您有所帮助!