POJ 1164 城堡问题【DFS/位运算/种子填充法/染色法】

1 2 3 4 5 6 7

#############################

1 # | # | # | | #

---#####---#---#####---#

2 # # | # # # # #

---#####---#####---#####---#

3 # | | # # # # #

---#########---#####---#---#

4 # # | | | | # #

#############################

(Figure 1)

= Wall

| = No wall

  • = No wall

Figure 1 shows the map of a castle.Write a program that calculates

  1. how many rooms the castle has
  2. how big the largest room is
    The castle is divided into m * n (m<=50, n<=50) square modules. Each such module can have between zero and four walls.
    Input
    Your program is to read from standard input. The first line contains the number of modules in the north-south direction and the number of modules in the east-west direction. In the following lines each module is described by a number (0 <= p <= 15). This number is the sum of: 1 (= wall to the west), 2 (= wall to the north), 4 (= wall to the east), 8 (= wall to the south). Inner walls are defined twice; a wall to the south in module 1,1 is also indicated as a wall to the north in module 2,1. The castle always has at least two rooms.
    Output
    Your program is to write to standard output: First the number of rooms, then the area of the largest room (counted in modules).
    Sample Input
    4
    7
    11 6 11 6 3 10 6
    7 9 6 13 5 15 5
    1 10 12 7 13 7 5
    13 11 10 8 10 12 13
    Sample Output
    5
    9
    【题意】:给出一个 n*m 矩阵,矩阵代表了一个大房间,然后矩阵的每个元素代表了该模块的信息,用 1 表示 WEST 方向是墙壁,2 表示 NORTH 方向是墙, 4 表示 EAST 方向是墙, 8 表示 SOUTH 方向是墙,题目所给矩阵的元素值就是该模块所有墙壁数值总和,现在要求统计这个大房间被分成了几个区域,其中最大区域包含几个模块。
    【分析】:关键是怎么把数字矩阵转化成我们想要的图形矩阵,就是从一个模块所有墙壁数值总和看出这个模块都有哪几面墙,这是这道题的亮点。
    1 的2进制 0001,2 的是 0010,4 的是 0100,8 的是 1000,例如 11 取2进制 1011,只有 4 和 11 取 & 运算是 0 ,即该模块在 4 方向(也就是 EAST 方向)是通的。

把方块看作是节点,相邻两个方块之间如果没有墙,则在方块之间连一条边,这样城堡就能转换成一个图。

求房间个数,实际上就是在求图中有多少个极大连通子图。

一个连通子图,往里头加任何一个图里的其他点,就会变得不连通,那么这个连通子图就是极大连通子图。(如:(8,5,6))

对每一个房间,深度优先搜索,从而给这个房间能够到达的所有位置染色。最后统计一共用了几种颜色,以及每种颜色的数量。

比如

1122333

1112343

1115353

1555553

从而一共有5个房间,最大的房间(1)占据9个格子

【注意】:这个题是没有已知的终点的,所以在判断是否停下的时候只能使用标记来进行停止到最后一个

#include<cstdio>
#include<string>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<cctype>
#include<stack>
#include<sstream>
#include<list>
#include<assert.h>
#include<bitset>
#include<numeric>
#define debug() puts("++++")
#define gcd(a,b) __gcd(a,b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a,b,sizeof(a))
#define sz size()
#define be begin()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
#define all 1,n,1
#define rep(i,n,x) for(int i=(x); i<(n); i++)
#define in freopen("in.in","r",stdin)
#define out freopen("out.out","w",stdout)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e18;
const int maxn = 1e6;
const int maxm = 100;
const double PI = acos(-1.0);
const double eps = 1e-8;
//const int dx[] = {-1,1,0,0,1,1,-1,-1};
//const int dy[] = {0,0,1,-1,1,-1,1,-1};
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int n, m;
int num=0,ans,Max=0,tot=0;
int a[maxm][maxm];//1左 2上 4右 8下
int vis[maxm][maxm];

void dfs(int i,int j)
{
    if(vis[i][j]) return ;
    tot++; //
    vis[i][j]=num; //染色
    if((a[i][j]&1)==0) dfs(i,j-1);
    if((a[i][j]&2)==0) dfs(i-1,j);
    if((a[i][j]&4)==0) dfs(i,j+1);
    if((a[i][j]&8)==0) dfs(i+1,j);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    ms(vis,0);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(!vis[i][j])
            {
                tot=0;
                num++;
                dfs(i,j);
                Max = max(Max,tot);
            }
        }
    }
    printf("%d\n%d\n",num,Max);
}
/*
4
7
11 6 11 6 3 10 6
7 9 6 13 5 15 5
1 10 12 7 13 7 5
13 11 10 8 10 12 13
*/

posted @ 2018-06-17 10:21  Roni_i  阅读(188)  评论(0编辑  收藏  举报