Section 2.1 castle

题目大意:

    给出一个城堡的平面图(考虑只有一层),城堡四周自然被墙包围,城堡中也有一些墙,这些墙与四周的墙构成了若干个房间。且如果推倒两个房间之间的墙,那么两个房间便会变成一个房间,那么易知会存在一堵墙(也可能不止一个)被推倒后会产生一个最大房间。
    求城堡一共有几个房间,并且求推倒后能够产生最大房间的那堵墙。
    下为城堡平面示意图:
    1   2   3   4   5   6   7
   #############################
 1 #   |   #   |   #   |   |   #
   #####---#####---#---#####---#   
 2 #   #   |   #   #   #   #   #
   #---#####---#####---#####---#
 3 #   |   |   #   #   #   #   #   
   #---#########---#####---#---#
 4 # ->#   |   |   |   |   #   #   
   ############################# 

    # =墙壁    -,| = 没有墙壁
 -> =指向一面墙,这面墙推掉的话我们就有一间最大的新房间

      这个城堡的平面图是7×4个单位的。一个“房间”的是平面图中一个由“#”、“-”、“|”围成的格子(就是图里面的那一个个的格子)。比如说这个样例就有5个房间。(大小分别为9、7、3、1、8个单位(排名不分先后))
      移去箭头所指的那面墙,可以使2个房间合为一个新房间,且比移去其他墙所形成的房间都大。
      城堡保证至少有2个房间,而且一定有一面墙可以被移走。
输入格式
    第一行有两个整数:M和N 城堡的平面图用一个由数字组成的矩阵表示,一个数字表示一个单位,矩阵有N行M列。输入与样例的图一致。
    每一个单位的数字告诉我们这个单位的东西南北是否有墙存在。每个数字是由以下四个整数的某个或某几个加起来的(四面都没有墙的话,这个数字应该为0)。
    1: 在西面有墙      2: 在北面有墙
    4: 在东面有墙      8: 在南面有墙
提示:城堡内部的墙会被规定两次。比如说(1,1)南面的墙,亦会被标记为(2,1)北面的墙。
输出格式
输出包含如下4行:
第 1 行: 城堡的房间数目。
第 2 行: 最大的房间的大小
第 3 行: 移除一面墙能得到的最大的房间的大小
第 4 行: 移除哪面墙可以得到面积最大的新房间。
    选择最佳的墙来推倒。有多解时选最靠西的,仍然有多解时选最靠南的。同一格子北边的墙比东边的墙更优先。
    用该墙的南邻单位的北墙或西邻单位的东墙来表示这面墙,方法是输出邻近单位的行数、列数和墙的方位("N"(北)或者"E"(东))。
样例输入
line 1: 7 4
line 2-N+1: 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
样例输出
line 1: 5
line 2: 9
line 3: 16
line 4: 4 1 E

题解

    这道题我超时了很久,最后也没有想出什么好办法,主要是test里面的一组50X50的房间,每个房间只有一个单位大小。这个test在我程序里跑不出来,后来没办法,只能先取个巧,避过了这组test,然后通过了。。。。。。
    题目要求的比较多,首先是由几个房间,这个比较简单,深搜就行了。在深搜的过程中,给每个房间标号,这样可以方便的知道每个房间的大小,第二问求最大房间大小就很简单了。
    然后就是求推倒一座墙之后,可以构成一个最大的房间,我的做法是,把可能的最大房间大小从大到小排序,然后判断是否可以推倒某堵墙实现这个可能。这里也体现了之前给每个房间标号的作用。比较麻烦的是,可能有多堵墙可以实现最大房间,所以需要根据题目给出的优先顺序给出墙的位置。(其中很坑的是,当判断两房间是否可以组成最大房间的时候,由于涉及到一个为基准的问题,所以如果这两个房间可以组成最大房间,那么还要将这两个房间交换一下,再找一遍,依此找到最符合题目要求的墙,具体见程序)

代码

#include<stdio.h>
    int N=0,M=0,m=0,room[51][51][5]={0};//M wei hang;N wei lie
    int flag=0,cnt[25000]={0},g[4000000][3]={0};
    int xy[2500][3]={0},p=0,flag1=0,flag2=0;
    int v=0;
    int count(int room[51][51][5])
    {
    int i,j;
        for(i=0;i<M;i++)
            for(j=0;j<N;j++)
                cnt[room[i][j][4]]++;
    return 0;
    }
    int mark(int room[51][51][5],int x,int y,int m)
    {
    if(x<0||y<0||x>=M||y>=N)
        return 0;

    if(room[x][y][4]==10000)
            {
                flag=1;
                room[x][y][4]=m;
                if(room[x][y][0]==0)
                    mark(room,x,y-1,m);
                if(room[x][y][1]==0)
                    mark(room,x-1,y,m);
                if(room[x][y][2]==0)
                    mark(room,x,y+1,m);
                if(room[x][y][3]==0)
                    mark(room,x+1,y,m);

            }
    return 0;

    }
    int fid(int room[51][51][5],int a,int b)
    {


    int i,j;
    for(j=0;j<N;j++)
        for(i=M-1;i>=0;i--)
        {
            if(room[i][j][4]==a)
            {

                if(room[i][j][0]==1)
                {

                    flag2=0;
                    if(i<0||j<1||i>=M||j>=N+1)
                        flag2=1;

                    if(room[i][j-1][4]==b&&flag2==0)
                    {

                        flag1=1;
                        xy[p][0]=i;
                        xy[p][1]=j;
                        xy[p][2]=1;
                        p++;
                    }
                }
                if(room[i][j][1]==1)
                {
                    flag2=0;
                    if(i<1||j<0||i>=M+1||j>=N)
                        flag2=1;

                    if(room[i-1][j][4]==b&&flag2==0)
                    {
                        flag1=1;
                        xy[p][0]=i;
                        xy[p][1]=j;
                        xy[p][2]=2;
                        p++;
                    }
                }
                if(room[i][j][2]==1)
                {
                    flag2=0;
                    if(i<0||j<-1||i>=M||j>=N-1)
                        flag2=1;

                    if(room[i][j+1][4]==b&&flag2==0)
                    {
                        flag1=1;
                        xy[p][0]=i;
                        xy[p][1]=j;
                        xy[p][2]=3;
                        p++;
                    }
                }
                if(room[i][j][3]==1)
                {
                    flag2=0;
                    if(i<-1||j<0||i>=M-1||j>=N)
                        flag2=1;

                    if(room[i+1][j][4]==b&&flag2==0)
                    {
                        flag1=1;
                        xy[p][0]=i;
                        xy[p][1]=j;
                        xy[p][2]=4;
                        p++;
                    }
                }
            }
        }
        return 0;
    }
    int main()
    {

    int xy1,xy2,xy3;
    int sum,max,mmax;
    long int i,j;
    long int k=0,t;
    m=1;
    scanf("%d %d",&N,&M);
    for(i=0;i<M;i++)
        for(j=0;j<N;j++)
        {
            scanf("%ld",&t);
            room[i][j][0]=t%2;
            t=t/2;
            room[i][j][1]=t%2;
            t=t/2;
            room[i][j][2]=t%2;
            t=t/2;
            room[i][j][3]=t%2;
            room[i][j][4]=10000;

        }
        for(j=0;j<N;j++)
            for(i=M-1;i>=0;i--)
            {
                flag=0;
                mark(room,i,j,m);
                if(flag==1)
                    m++;
            }
    /*  for(i=0;i<M;i++)
            for(j=0;j<N;j++)
            {
                printf("%d\n",room[i][j][4]);
            }*/
        count(room);
        sum=m-1;
        max=cnt[1];
        for(i=1;i<m;i++)
        {
            if(max<cnt[i])
                max=cnt[i];
        }

            k=0;
        for(t=2500-sum+2;t>0;t--)
        for(i=1;i<m;i++)
            for(j=i+1;j<m;j++)
            {
                if(t==cnt[i]+cnt[j]&&k<40000)//这里有取巧,即k<40000。这个限定没有任何逻辑依据,只是在避免上文说的那个情况,为什么我认为k<40000就可以出答案了呢,因为我标号和找房间的时候是按照题目给的方向顺序的,所以如果碰到大量面积相同的房间的时候,取得便是方位更优的房间。
                {g[k][0]=t;
                g[k][1]=i;
                g[k][2]=j;
                k++;}
            }

        //  for(i=0;i<k;i++)
        //      printf("%d %d %d\n",g[i][0],g[i][1],g[i][2]);
        for(i=0;i<k;i++)
        {
            flag1=0;
            fid(room,g[i][1],g[i][2]);
            if(flag1==1)
            {mmax=g[i][0];break;}
        }
        xy1=xy[0][0];xy2=xy[0][1];xy3=xy[0][2];
        p=0;
        fid(room,g[i][2],g[i][1]);//这里就是上文说的将两个房间顺序颠倒,然后取最满足题目要求的。
        if(xy2<xy[0][1])
        {
            xy[0][0]=xy1;
            xy[0][1]=xy2;
            xy[0][2]=xy3;
        }
        if(xy2==xy[0][1]&&xy1>xy[0][0])
        {
            xy[0][0]=xy1;
            xy[0][1]=xy2;
            xy[0][2]=xy3;
        }
        printf("%d\n%d\n%d\n%d %d ",sum,max,mmax,xy[0][0]+1,xy[0][1]+1);
        if(xy[0][2]==1)
            printf("%c\n",'W');
        if(xy[0][2]==2)
            printf("%c\n",'N');
        if(xy[0][2]==3)
            printf("%c\n",'E');
        if(xy[0][2]==4)
            printf("%c\n",'S');
        return 0;


    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值