USACO The Castle 种子染色法


Translate:USACO/castle

The Castle城堡

IOI'94 - Day 1

目录

 [隐藏

[编辑]描述

我们憨厚的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个房间,而且一定有一面墙可以被移走。

[编辑]格式

PROGRAM NAME: castle

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

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

1: 在西面有墙
2: 在北面有墙
4: 在东面有墙
8: 在南面有墙

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


OUTPUT FORMAT:

(file castle.out)

输出包含如下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


原来写过很多遍的这种方法叫做种子染色法。

/*
ID: 17702791
PROG: castle
LANG: C++
*/
#include<bits/stdc++.h>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define ysk(x)   (1<<(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn= 50   ;
int m,n;
int a[maxn+10][maxn+10];
int com[maxn+10][maxn+10],ncom,scom[maxn+10];
int dir[4][2]={ {0,-1},{-1,0},{0,+1},{+1,0},  };//w n e s
int val[4]={100,50  ,25 , 75   };
char name[4]={'W', 'N' ,'E', 'S'   };


struct A
{
    int y,x,ans,fac;
    void insert(int tans,int tfac,int ty,int tx)
    {
        if(tans>ans)
        {
            ans=tans;
            fac=tfac;
            y=ty;
            x=tx;
        }
        else if(tans==ans&& tx<x )
        {
              fac=tfac;
              y=ty;
              x=tx;
        }
        else if(tans==ans&& tx==x&&ty>y)
        {
            fac=tfac;
            y=ty;
        }
        else if(tans==ans&& tx==x&&ty==y&&val[tfac]>val[fac])
        {
              fac=tfac;
        }
    }
    void out()
    {
        cout<<ans<<endl;
        cout<<y<<" "<<x<<" "<<name[fac]<<endl;
    }

    void clear()// at least two room
    {
        ans=-1;
        fac=-1;
        y=x=-1;
    }


} Ans;


bool in(int &y ,int &x)
{
    return 1<=y&&y<=n&&1<=x&&x<=m;
}
void dfs(int y,int x)
{
   for0(j,4) if(! ( a[y][x]&ysk(j) ) )
   {
       int ty=y+dir[j][0];
       int tx=x+dir[j][1];
       if(!in(ty,tx)|| ~com[ty][tx])  continue;
       scom[ncom]++;
       com[ty][tx]=ncom;
       dfs(ty,tx);
   }

}

void solve()
{
    Ans.clear();
   for1(y,n) for1(x,m)
   {
       int c1=com[y][x];
       int s1=scom[c1];
       for(int i=1;i<=2;i++)  if(  a[y][x]&ysk(i))
       {
            int ty=y+dir[i][0];
            int tx=x+dir[i][1];

            if(!in(ty,tx))  continue;
            int c2=com[ty][tx]; if(c1==c2)  continue;
            int s2=scom[c2];
            int tmp=s1+s2;
            Ans.insert(tmp,i,y,x);

       }
   }
   Ans.out();
}

void work()
{
    memset(com,-1,sizeof com);
    ncom=0;
    int maxi=1;
    for1(i,n) for1(j,m)  if(com[i][j]==-1)
    {
        ncom++;
        com[i][j]=ncom;
        scom[ncom]=1;
        dfs(i,j);
        maxi=max(maxi,scom[ncom]);
    }
    cout<<ncom<<endl;
    cout<<maxi<<endl;


}
int main()
{
   freopen("castle.in","r",stdin);
   freopen("castle.out","w",stdout);

    cin>>m>>n;
    for1(i,n)  for1(j,m) scanf("%d",&a[i][j]);

   work();
   solve();

   return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值