POJ(116,1718)-----The Castle(openjudge)

来源:互联网 发布:网王之数据大师 编辑:程序博客网 时间:2024/06/11 12:07

The Castle

Description

                 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

Source

IOI 1994

做题地址:NOI.openjudge-116.The Castle(需要注册)
翻译题目地址(我知道你们要这个):NOI.openjudge-1817.城堡问题(需要注册)


首先,这是一道
其次,这是一道
最后,这是一道

O(∩_∩)O~

水题代码在此

#include<cstdio>int main(){    while(1)        printf("水题\n");    return 0;}

初步分析题目可得:

1:这其实就是求最大连通块的“变异”版本
2:求最大连通块使用dfs比较方便
3:输入数据是周围墙的和

所以,需要先处理的是数据中的墙(此题重点在处理墙)


说到处理墙,首先想到的是使用“边界”墙暴力推出其他墙
但是——内墙的中间部分推不出来

再来看看东,西,南,北墙的数据:

西墙:1=2^0
北墙:2=2^1
东墙:4=2^2
南墙:8=2^3

也就是:

西墙:1(10)= 0 0 0 1(2)
北墙:2(10)= 0 0 1 0(2)
东墙:4(10)= 0 1 0 0(2)
南墙:8(10)= 1 0 0 0(2)

把数据转化成二进制后,各位数相加并不冲突,举栗:

西墙+北墙:3(10) = 0 0 1 0

所以处理墙的问题可以用位运算解决


位运算是个啥玩意儿?
位运算_百度百科(你不想看百度也可以)

为运算就是把数化成二进制后对二进制上的数位进行操作
C++中一共有6种位运算符(“&”,“|”,“~”,“^”,“>>”,“<<”)
这里只介绍需要使用的两种:

1:“&”按位与:
跟与运算(“&&”)有异曲同工之妙,只是“&”是把数转化成二进制后,每一位进行“&&”。

举栗:

9&5
=1001(2)& 0101(2)
=0001(2)
=1

用途:
根据“&”的特性,任意数&1=此数末位(2)&1,此时如果末位为1,则返回1,反之返回0。所以“&”可以判断奇偶或检查末位数字(二进制)

本题用途:
检查末位的位置是否有墙

2:“>>”右移
一个令人匪夷所思的位运算,具体看栗;

15>>3
=1111(2)>>3
=0111(2)>>2
=0011(2)>>1
=0001(2)
=1

用途:
简单点说,就是一个数>>x,就删除此数末位的x位(二进制)
把二进制上的某一位移至末位

此题用途:
把其他墙的判断移至末尾

把这两种运算组合使用,就可以得出每个方块周围是否有墙。


附代码一份

#include<cstdio>#include<iostream>#include<algorithm>using namespace std;struct data{    bool m[4];    int p,t;}map[55][55];int n,m,tot,Max,s,f[4][2]={{0,-1},{-1,0},{0,1},{1,0}};void change(data &x){    int k=0;    while(x.p!=0)    {        x.m[k]=x.p&1;        x.p>>=1;        k++;    }}void dfs(int x,int y,int id){    if(map[x][y].t) return ;    map[x][y].t=id;    map[x][y].p=s;    s++;    for(int i=0;i<4;i++)        if(!map[x][y].m[i])            dfs(x+f[i][0],y+f[i][1],id);}int main(){    scanf("%d %d",&n,&m);    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        {            scanf("%d",&map[i][j].p);            change(map[i][j]);        }    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            if(!map[i][j].t)            {                s=1;                dfs(i,j,++tot);            }    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            Max=max(Max,map[i][j].p);    printf("%d\n%d\n",tot,Max);}

IN THE END

判断是否有墙有两种方法,代码只提供了一种
只需要改change函数就可以实现第二种方法

void change(data &x){    int k=0;    for(int i=0;i<4;i++)    {        x.m[k]=x.p&pow(2,i)>>i;//pow函数包含在<cmath>中,意义为2^i        k++;    }}

改的原因自己想