洛谷P1764 翻转游戏(加强版)


题目

https://www.luogu.com.cn/problem/P1764

思路

其实这是当年高三时模拟赛的一道题,当时写了个假的贪心水了40分,结果教练让我上去讲题,就不得不学了一下。

后来看电视节目的时候发现这个题的变种在《最强大脑》里出现了,也算是一个经典的模型吧。

这道题其实需要一点意会。。。(描述简单起见,将翻转第x行第y列方格为中心的十字这个操作称为\(flip(x,y)\),将方阵称为\(a\),第\(i\)行第\(j\)列称为\(a[i][j]\)

很显然这个翻转操作是会影响上面一行的,乍看决策之间是相互影响的。但是,考虑到第一行不存在上一行,我们珂以 \(2^n\) 枚举第一行的每一格是否执行\(flip\)操作。

不妨以改成全白为例:

逐行处理,对于\(1到n-1\)行,挨个检查\(a[i][j]\)是否为白色,如果为白色不操作,如果为黑色执行\(flip(i+1,j)\)(为什么不能是\(flip(i,j)\)?因为这会导致我们之前已经钦定好的格子发生改变)

对于第\(n\)行,如果不是全白,那么说明第一行的该决策无可行解,直接返回\(inf\)

简而言之,就是说只要第一行的决策确定,那么整个方阵的最优解就确定了。

代码

点击查看代码
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
char a[17][17];
int n;
int tmp[17][17];
void input(){
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;++i) scanf("%s",a[i]+1);
}
void reset(){
    int i,j;
    for(i=1;i<=n;++i)
        for(j=1;j<=n;++j)
            tmp[i][j]=(a[i][j]=='w'?0:1);
}
void flip(int x,int y){
    tmp[x][y]^=1;
    if(x>1) tmp[x-1][y]^=1;
    if(x1) tmp[x][y-1]^=1;
    if(y