P1457 城堡 The Castle 位运算+BFS+思维(难题,好题)

题目描述
我们憨厚的USACO主人公农夫约翰(Farmer John)以无法想象的运气,在他生日那天收到了一份特别的礼物:一张“幸运爱尔兰”(一种彩票)。结果这张彩票让他获得了这次比赛唯一的奖品——坐落于爱尔兰郊外的一座梦幻般的城堡!

喜欢吹嘘的农夫约翰立刻回到有着吹嘘传统的威斯康辛老家开始吹嘘了, 农夫约翰想要告诉他的奶牛们关于他城堡的一切。他需要做一些吹嘘前的准备工作:比如说知道城堡有多少个房间,每个房间有多大。另外,农夫约翰想要把一面单独的墙(指两个单位间的墙)拆掉以形成一个更大的房间。 你的工作就是帮农夫约翰做以上的准备,算出房间数与房间的大小。

城堡的平面图被划分成M*N(1 <=M,N<=50)个正方形的单位,一个这样的单位可以有0到4面墙环绕。城堡周围一定有外墙环绕以遮风挡雨。(就是说平面图的四周一定是墙。)

请仔细研究下面这个有注解的城堡平面图:

友情提示,这个城堡的平面图是7×4个单位的。一个“房间”的是平面图中一个由“#”、“-”、“|”围成的格子(就是图里面的那一个个的格子)。比如说这个样例就有5个房间。(大小分别为9、7、3、1、8个单位(排名不分先后))

移去箭头所指的那面墙,可以使2个房间合为一个新房间,且比移去其他墙所形成的房间都大。(原文为:Removing the wall marked by the arrow merges a pair of rooms to make the largest possible room that can be made by removing a single wall. )

城堡保证至少有2个房间,而且一定有一面墙可以被移走。

输入输出格式
输入格式:
第一行有两个整数:M和N 城堡的平面图用一个由数字组成的矩阵表示,一个数字表示一个单位,矩阵有N行M列。输入与样例的图一致。

每一个单位的数字告诉我们这个单位的东西南北是否有墙存在。每个数字是由以下四个整数的某个或某几个或一个都没有加起来的。

1: 在西面有墙

2: 在北面有墙

4: 在东面有墙

8: 在南面有墙

城堡内部的墙会被规定两次。比如说(1,1)南面的墙,亦会被标记为(2,1)北面的墙。

输出格式:
输出包含如下4行:

第 1 行: 城堡的房间数目。

第 2 行: 最大的房间的大小

第 3 行: 移除一面墙能得到的最大的房间的大小

第 4 行: 移除哪面墙可以得到面积最大的新房间。

选择最佳的墙来推倒。有多解时选最靠西的,仍然有多解时选最靠南的。同一格子北边的墙比东边的墙更优先。

用该墙的南邻单位的北墙或西邻单位的东墙来表示这面墙,方法是输出邻近单位的行数、列数和墙的方位(“N”(北)或者"E"(东))。

输入输出样例
输入样例#1:
7 4
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
输出样例#1:
5
9
16
4 1 E
说明
USACO 2.1

翻译来自NOCOW

这个题就是怎么拆一面墙使的房间面积最大,这里有一个坑,就是最大的房间不一定是两间房的和,毕竟好几间房相连,有时候会比大房子大!

#include <bits/stdc++.h>
using namespace std;
int n,m,h[55][55],a[55][55][4],s,ans,z1,z2;
int q1[10010],q2[10010],f[10010];
int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0};
char z3;
string z="WNEA";
int main(){
    cin>>m>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            int x;
            cin>>x;
            if(x&1)a[i][j][0]=1;
            if(x&2)a[i][j][1]=1;
            if(x&4)a[i][j][2]=1;
            if(x&8)a[i][j][3]=1;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(!h[i][j]){
                int front=0,rear=1,sum=1;
                q1[1]=i;
                q2[1]=j;
                h[i][j]=++s;
                while(front<rear){
                    front++;
                    int x=q1[front],y=q2[front];
                    for(int k=0;k<=3;k++){
                        int tx=x+dx[k],ty=y+dy[k];
                        if(tx>0&&tx<=n&&ty>0&&ty<=m&&!h[tx][ty]&&!a[x][y][k]){
                            h[tx][ty]=s;
                            sum++;
                            q1[++rear]=tx;
                            q2[rear]=ty;
                        }
                    }
                }ans=max(ans,sum);
                f[s]=sum;
            }
    cout<<s<<endl<<ans<<endl;
    for(int j=1;j<=m;j++)
        for(int i=n;i>=1;i--)
            for(int k=1;k<=2;k++)
                if(a[i][j][k]){
                    int tx=i+dx[k],ty=j+dy[k];
                    int x=f[h[tx][ty]]+f[h[i][j]];
                    if(x>ans&&h[tx][ty]!=h[i][j]){
                        ans=x;
                        z1=i;
                        z2=j;
                        z3=z[k];
                    }
                }
    cout<<ans<<endl<<z1<<" "<<z2<<" "<<z3;
    return 0;
}
posted @ 2019-06-22 21:48  风骨散人  阅读(189)  评论(0编辑  收藏  举报