USACO 2.1.1The Castle城堡

来源:互联网 发布:cydia软件源更新 编辑:程序博客网 时间:2024/04/24 00:28

Problem A: 2.1.1The Castle城堡

Time Limit: 1 Sec  Memory Limit: 64 MB
Submit: 22  Solved: 5
[Submit][Status][Web Board]

Description

我们憨厚的USACO主人公农夫约翰(Farmer John)以无法想象的运气,在他生日那天收到了一份特别的礼物:一张“幸运爱尔兰”(一种彩票)。结果这张彩票让他获得了这次比赛唯一的奖品——坐落于爱尔兰郊外的一座梦幻般的城堡!喜欢吹嘘的农夫约翰立刻回到有着吹嘘传统的威斯康辛老家开始吹嘘了, 农夫约翰想要告诉他的奶牛们关于他城堡的一切。他需要做一些吹嘘前的准备工作:比如说知道城堡有多少个房间,每个房间有多大。另外,农夫约翰想要把一面单独的墙(指两个单位间的墙)拆掉以形成一个更大的房间。你的工作就是帮农夫约翰做以上的准备,算出房间数与房间的大小。城堡的平面图被划分成M*N(1 <=M,N<=50)个正方形的单位,一个这样的单位可以有0到4面墙环绕。城堡周围一定有外墙环绕以遮风挡雨。(就是说平面图的四周一定是墙。)请仔细研究下面这个有注解的城堡平面图:
 1   2   3   4   5   6   7  #############################1 #   |   #   |   #   |   |   #  #####---#####---#---#####---#   2 #   #   |   #   #   #   #   #  #---#####---#####---#####---#3 #   |   |   #   #   #   #   #     #---#########---#####---#---#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个房间,而且一定有一面墙可以被移走。

Input

城堡的平面图用一个由数字组成的矩阵表示,一个数字表示一个单位,矩阵有N行M列。输入与样例的图一致。每一个单位的数字告诉我们这个单位的东西南北是否有墙存在。每个数字是由以下四个整数的某个或某几个或一个都没有加起来的。1: 在西面有墙2: 在北面有墙4: 在东面有墙8: 在南面有墙城堡内部的墙会被规定两次。比如说(1,1)南面的墙,亦会被标记为(2,1)北面的墙。

Output

输出包含如下4行:第 1 行: 城堡的房间数目。第 2 行: 最大的房间的大小第 3 行: 移除一面墙能得到的最大的房间的大小第 4 行: 移除哪面墙可以得到面积最大的新房间。选择最佳的墙来推倒。有多解时选(重心)最靠西的(仍然有多解时选这些里面(重心)最靠南的)。用该墙的南邻单位的北墙或西邻单位的东墙来表示这面墙,方法是输出邻近单位的行数、列数和墙的方位("N"(北)或者"E"(东))。

Sample Input

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

Sample Output

5
9
16
4 1 E


解题思路:DFS  深度优先搜索

  1、二维数组a1[i][j]存储各表征每个房间的信息;       三维数组a2[i][j][4]存储a1[i][j]中的二进制表示,(化为二进制后,a2[i][j]中的每一位表示这个房间某一面墙通或不通。
   2、二维数组visit1[i][j]表示与这个房间相同的房间总数;      二维数组visit2[i][j]表示相连后各大房间的房间号(如第一次深搜得到的一个大房间,房间号为1......)。
   3、一维数组b1[i]表示个各大房间所包含的小房间数,便于输出。
   4、找可以移除的墙,即是找不同的大房间号相夹(a2[i][j]不同),且两大房间面积总和最大(a1[i][j]相加最大)。

细节:1、每次判断完一个房间一面墙后,将这个房间的这面墙由通变为不通(由0变为1),并且将与这间房间相通的房间的这面墙也改为不通,以避免重复搜索。然后再进行下一个房间的搜索。
             2、找可以移除的墙的时候,从下向上遍历,从左向右遍历。




代码:
#include <iostream>
using namespace std;

int a1[55][55],a2[55][55][5],visit1[55][55],visit2[55][55];
int b1[5000];
int n,m;
int i,j,k,k1,max1;
void zhuanhua(int x)
{
    int t=4;
    while(x>0)
    {
        a2[i][j][t]=x%2;
        x/=2;
        t--;
    }
}

void DFS(int i,int j)
{
    int t;

    visit1[i][j]=-1;
    for(t=1;t<=4;t++)
    {
        if(a2[i][j][t]==0)
        {
            a2[i][j][t]=1;
            switch(t)
            {
                case 1:
                    a2[i+1][j][3]=1;
                    DFS(i+1,j);
                    break;
                case 2:

                    a2[i][j+1][4]=1;
                    DFS(i,j+1);
                    break;
                case 3:
                    a2[i-1][j][1]=1;        
                    DFS(i-1,j);
                    break;
                case 4:
                    a2[i][j-1][2]=1;
                    DFS(i,j-1);
                    break;        
            }
        }
    }
}

int main()
{
    
    int t,s,r;
    cin>>m>>n;
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            cin>>a1[i][j];
            zhuanhua(a1[i][j]);
        }

    k1=0;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            if(visit1[i][j]==0)
            {
                DFS(i,j);
                int ct3=0;
                for(s=1;s<=n;s++)
                    for(k=1;k<=m;k++)
                    {
                        if(visit1[s][k]==-1)
                        {
                            ct3++;
                        }
                    }
                for(s=1;s<=n;s++)
                    for(k=1;k<=m;k++)
                    {
                        if(visit1[s][k]==-1)
                        {
                            visit1[s][k]=ct3;
                            visit2[s][k]=k1+1;
                        }
                    }
                b1[k1++]=ct3;
            }

            
        }
    }

    max1=0;
    for(i=0;i<k1;i++)
    {
        if(b1[i]>max1)
            max1=b1[i];
    }
    cout<<k1<<endl;
    cout<<max1<<endl;

    int max2=0,fx,i1,j1;
    for(j=1;j<=m;j++)
    {
        for(i=n;i>=1;i--)
        {
            if(visit2[i][j]!=visit2[i-1][j]  && i-1>=1 && visit1[i][j]+visit1[i-1][j]>max2)
            {
                max2=visit1[i][j]+visit1[i-1][j];
                i1=i;
                j1=j;
                fx=1;
            }            
        }

        for(i=n;i>=1;i--)
        {
            if(visit2[i][j]!=visit2[i][j+1]  && j+1<=m && visit1[i][j]+visit1[i][j+1]>max2)
            {
                max2=visit1[i][j]+visit1[i][j+1];
                i1=i;
                j1=j;
                fx=2;
            }
            
        }
    }
        
    cout<<max2<<endl;
    cout<<i1<<" "<<j1<<" ";
    if(fx==1)
        cout<<"N";
    else
        cout<<"E";

    return 0;
}