noi.ac #536 打地鼠

题目链接:戳我

【问题描述】

小A在玩打地鼠游戏。有一个n×m的网格,每个位置上地鼠都会要么冒出头要么缩进去。地鼠很狡猾,每次小A选一个地鼠冒出头的格子(x,y)把它打下去,但同一行同一列的地鼠全都会冒出头来。

小A发现这个游戏好像怎么都玩不完。这个时候小B过来向他展示真正的技术了。小B当然也知道这游戏是玩不完的,于是他准备了两个状态,并准备向小A表演把状态1进行若干次打地鼠操作变成状态2。

现在小B想知道他会不会翻车。

【输入格式】

第一行两个整数n,m表示棋盘大小n行m列。

接下来n行,每行一个长为m的字符串描述初始状态,'O'表示地鼠冒出头来,'X'表示地鼠缩了进去。

接下来n行,每行一个长为m的字符串描述结束状态,格式同上。

【输出格式】

如果能从初始状态变成目标状态输出1,否则输出0。

【样例输入】

4 4
XOOO
XXXX
XOOX
XOXO
OXOO
XOOO
XOOO
OOOO

【样例输出】

1

【数据规模】

subtask1(20'):n,m≤4。
subtask2(30'):n,m≤50。
subtask3(50'):n,m≤1000。


用黑色表示缩下去,白色表示冒出头。
每次操作相当于选一个白的变成黑的,但这行这列都会变成白的。

考虑倒着做。用灰色表示可能是黑也可能是白。
那么操作就变成了:选一个黑色或灰色的,必须满足这行这列除了它没有黑色,把它变成白色并把这行这列变成灰色。

注意到要操作一个黑色时,这行这列除了它就没有黑色了,所以操作之间不会干扰,直接能做就做就行了。

最后判下灰色的行列的交界处必须至少有一个白色(要进行第一步操作)。其它位置必须对应相等。
还要特判下如果一开始两个状态就相等输出1。

复杂度O(nm)。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define mp make_pair
#define MAXN 1010
using namespace std;
int n,m;
int a[MAXN][MAXN],b[MAXN][MAXN],cnt_hang[MAXN],cnt_lie[MAXN];
int done[MAXN][MAXN],done_hang[MAXN],done_lie[MAXN];
char s[MAXN][MAXN],t[MAXN][MAXN];
queue<pair<int,int> >q;
//倒着做 相当于把0变成1 QAQ
inline bool check_the_same()
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]!=b[i][j]) return false;
    return true;
}
inline bool check_s()
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]!=0) return false;
    return true;
}
inline bool check_t()
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(b[i][j]!=1) return false;
    return true;
}
inline void paint(int x,int y)
{
    if(!done_hang[x])
    {
        done_hang[x]=1;
        for(int j=1;j<=m;j++)
        {
            if(j==y) continue;
            b[x][j]=-1;
            if(!cnt_lie[j]) q.push(mp(x,j));
        }
    }
    if(!done_lie[y])
    {
        done_lie[y]=1;
        for(int i=1;i<=n;i++)
        {
            if(i==x) continue;
            b[i][y]=-1;
            if(!cnt_hang[i]) q.push(mp(i,y));
        }
    }
}
inline bool solve()
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(b[i][j]==0&&cnt_hang[i]==1&&cnt_lie[j]==1)
            {
                q.push(mp(i,j));
                b[i][j]=-1;
                done[i][j]=1;
            }
    while(!q.empty())
    {
        int u_x=q.front().first;
        int u_y=q.front().second;
        q.pop();
        paint(u_x,u_y);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(b[i][j]!=-1&&a[i][j]!=b[i][j])
                return false;
    return true;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]=='O') a[i][j]=1;
            else a[i][j]=0;
        }
    for(int i=1;i<=n;i++) scanf("%s",t[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(t[i][j]=='O') b[i][j]=1;
            else b[i][j]=0,cnt_hang[i]++,cnt_lie[j]++;
        }
    if(check_the_same()) printf("1\n");
    else if(check_s()||check_t()) printf("0\n");
    else if(solve()) printf("1\n");
    else printf("0\n");
    return 0;
}
posted @ 2019-07-06 21:49  风浔凌  阅读(485)  评论(0编辑  收藏  举报