【二进制状态表示】 城堡问题

传送门

题意

\(n\times m\)的区域,每块墙有方向,其中上北下南左西右东,\(1\)表示西墙,\(2\)表示北墙,\(4\)表示东墙,\(8\)表示南墙,每个块中一个数字\(p\)表示上述表示墙的所有数字和,如\(p=3=1+2\),有西墙和北墙,每个墙计算\(2\)次,例如,\((2,2)\)的北墙也是\((1,2)\)的南墙,有墙的不是一个连通块,求最大的连通块

数据范围

\(1\leq n,m\leq 50\)
\(0\leq P\leq 15\)

题解

  • 按照二进制移位的次序,应该是左上右下

  • 左对应\((0,-1)\),上对应\((-1,0)\),右对应\((0,1)\),下对应\((1,0)\)

  • 数据保证了两个相邻墙的重合和不需要进行额外的判断

  • 数组坐标需要特别注意

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)

const int N=55;
int g[N][N];
int n,m;
bool st[N][N];
int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0};
int bfs(int x,int y)
{
    int res=0;
    queue<pair<int,int>>q;
    q.push(make_pair(x,y));
    st[x][y]=1;
    while(q.size())
    {
        pair<int,int> t=q.front();
        q.pop();
        ++res;
        rep(i,0,3)
        {
            int tx=t.first+dx[i],ty=t.second+dy[i];
            if(st[tx][ty]) continue;
            if(g[t.first][t.second] >>i&1) continue;
            if(tx>=1&&tx<=n&&ty>=1&&ty<=m)
            {
                st[tx][ty]=1;
                q.push(make_pair(tx,ty));
            }
        }
    }   
    return res;
}
int main(){
    cin>>n>>m;
    rep(i,1,n) rep(j,1,m)
        cin>>g[i][j];

    int cnt=0,s=0;
    rep(i,1,n) rep(j,1,m)
        if(!st[i][j]) s=max(s,bfs(i,j)),cnt++;

    cout<<cnt<<endl<<s<<endl;
} 
posted @ 2020-10-29 23:22  Hyx'  阅读(123)  评论(0)    收藏  举报