51nod1448 二染色问题(想法题,好题)

来源:互联网 发布:淘宝蚂蚁花呗怎么开通 编辑:程序博客网 时间:2024/06/05 15:37

题目链接

1448 二染色问题
题目来源: TopCoder
基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
 收藏
 关注
一个N*N的网格,初始为白色。现在有一个K*K的印章,每次操作:你可以用印章把网格中一个K*K的子矩形染成黑色或白色。如果一个格子被多次染色,那么后一次染色会覆盖掉前一次的。现在,给你N*N的由黑白两色构成的图案board(board[i][j]为第i行第j列格子的颜色,不是白字母‘W’表示,就是黑由字母‘B’表示),问是否能通过若干次操作,将网格从初始状态染成图案board的样子。如果可以输出"Possible",否则输出"Impossible".
Input
多组测试数据,第一行一个整数T,表示测试数据数量,1<=T<=5每组测试数据有相同的结构构成:每组数据一行两个整数N与K,其中1<=K<=N<=20。之后N行,每行N个字符,表示board,字符都由‘W’与‘B’构成。
Output
每组数据一行输出,即是否可能染出board图案来。
Input示例
34 3BBBWBWWWBWWWWWWW2 2BWWB6 2BWBWBBWBWBBBBWBWBBWBWBBBBBBBBBBBBBBB
Output示例
PossibleImpossiblePossible

官方题解

可以尝试逆向思维,最后一块无论是黑是白,都一定是k*k的连通块。倒数第i块,其一部分被最后的i-1块遮挡,其余部分必然同色且分布在k*k的矩形内。因此可以逆向贪心构造,直到每一个小正方形被覆盖为止。


其实这个题就像以前做过的一个贴海报的题目,首先确定一个全部为同色的k*k的块,然后将这些块内的格子标记为访问过了,对于后面的k*k的块,这时候只需要判断除了已经访问的点外,其他的是否为同色,知道找不到这样的块为止,到最后再扫一遍,若存在没被访问的且为black的就说明不存在解决方案。

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<queue>#include<stack>using namespace std;#define rep(i,a,n) for (int i=a;i<n;i++)#define per(i,a,n) for (int i=n-1;i>=a;i--)#define pb push_back#define fi first#define se secondtypedef vector<int> VI;typedef long long ll;typedef pair<int,int> PII;const ll mod=1000000007;const int maxn=20+10;char s[maxn][maxn];bool vis[maxn][maxn];int main(){    int cas;    scanf("%d",&cas);    while(cas--)    {        memset(vis,false,sizeof(vis));        int n,k;        scanf("%d%d",&n,&k);        bool flag=true;        for(int i=1;i<=n;i++) scanf("%s",s[i]+1);        while(flag)        {            flag=false;            for(int i=1;i<=n-k+1;i++)            {                for(int j=1;j<=n-k+1;j++)                {                    int sum1=0,sum2=0;                    bool f=false;                    for(int ii=i;ii<i+k;ii++)                    {                        for(int jj=j;jj<j+k;jj++)                        {                            if(vis[ii][jj]) continue;                            f=true;                            if(s[ii][jj]=='B') sum1++;                            else sum2++;                        }                    }                    if((sum1==0||sum2==0)&&f)                    {                        flag=true;                        for(int ii=i;ii<i+k;ii++)                        {                            for(int jj=j;jj<j+k;jj++)                                vis[ii][jj]=true;                        }                    }                }            }        }        bool f=true;        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)            {                if(!vis[i][j]&&s[i][j]=='B') f=false;            }        if(f) puts("Possible");        else puts("Impossible");    }    return 0;}


0 0
原创粉丝点击