USACO 2.1 The Castle___dfs+枚举

206 篇文章 0 订阅
78 篇文章 0 订阅

题目大意:

给出一副N*M的图,图上的任意一点[i,j]中四周可能存在墙壁,用ai,j描述周围的墙壁,
每个ai,j表示[i,j]东西南北是否有墙存在。每个数字是由以下四个整数的某个或某几个或一个都没。
1: 在西面有墙
2: 在北面有墙
4: 在东面有墙
8: 在南面有墙
求①城堡的房间数目②最大的房间的大小
③移除一面墙能得到的最大的房间的大小
④移除哪面墙可以得到面积最大的新房间。
选择最佳的墙来推倒。有多解时选最靠西的,仍然有多解时选最靠南的。同一格子北边的墙比东边的墙更优先。
用该墙的南邻单位的北墙或西邻单位的东墙来表示这面墙,方法是输出邻近单位的行数、列数和墙的方位(”N”(北)或者”E”(东))。

题解:

①仔细读题可知,
每个ai,j描述的是四周的墙壁的情况
墙壁并不存在坐标i,j,只是用于隔绝
②对图进行染色,找出房子数跟最大房子大小,dfs即可
时间复杂度:O(NM)
③考虑合并的最大值,
枚举每个坐标[i,j],判断一个向北推翻的最大合并值,一个向东的
④判断输出即可
这题好辣鸡、、一个细节我纠结了那么久

代码:

#include<bits/stdc++.h>
#define N 55

using namespace std;

const int dx[]={0,-1,0,1};
const int dy[]={-1,0,1,0};

int n,m,a[N][N],cnt[N][N],area[N*N],tot=0;

bool check(int x,int y) {
     if (x<1 || x>n || y<1 || y>m || cnt[x][y]) return 0;
     return 1;
}
void dfs(int x,int y,int z) {
     cnt[x][y]=z;
     area[z]++;
     for (int i=0; i<=3; i++)
         if (!( a[x][y] & (1<<i) )) {
            int x1=x+dx[i],y1=y+dy[i];
            if (check(x1,y1)) dfs(x1,y1,z);
         }
}

int main() {
    scanf("%d%d",&m,&n);
    for (int i=1; i<=n; i++) 
         for(int j=1; j<=m; j++) scanf("%d",&a[i][j]);
    for (int i=1; i<=n; i++) 
         for (int j=1; j<=m; j++)
              if (!cnt[i][j]) 
                 {
                     tot++;
                     dfs(i,j,tot);
                }
    int cmax=0;
    for (int i=1; i<=tot; i++)
         cmax=max(cmax,area[i]);
    printf("%d\n%d\n",tot,cmax);
    int ans1=cmax,ans2=cmax;
    int cp=0,x1=0,y1=0,x2=0,y2=0;
    for (int i=1; i<=n; i++)
         for (int j=1; j<=m; j++) {
             if ( (a[i][j]&2) && (cnt[i][j]!=cnt[i-1][j]) ){
                cp=area[cnt[i][j]]+area[cnt[i-1][j]];
                if (ans1<cp) { ans1=cp; x1=i; y1=j; }
                    else if (ans1==cp){ //就是这个辣鸡=号,我只打了一个一开始。。
                            if (j<y1) { x1=i; y1=j;}
                               else if (j==y1) x1=i;
                         }
                }
             if ( (a[i][j]&4) && (cnt[i][j]!=cnt[i][j+1]) ){
                cp=area[cnt[i][j]]+area[cnt[i][j+1]];
                if (ans2<cp) { ans2=cp; x2=i; y2=j; }
                    else if (ans2==cp){ //还有这个
                            if (j<y2) { x2=i; y2=j;}
                               else if (j==y2) x2=i;
                         }
                }
        }
    printf("%d\n",max(ans1,ans2));
    if (ans1>ans2) printf("%d %d N\n",x1,y1);
    if (ans1<ans2) printf("%d %d E\n",x2,y2);
    if (ans1==ans2){
              if (y1<y2) printf("%d %d N\n",x1,y1);
         else if (y1>y2) printf("%d %d E\n",x2,y2);
         else if (x1>x2) printf("%d %d N\n",x1,y1);
         else if (x1<x2) printf("%d %d E\n",x2,y2);
         else printf("%d %d N\n",x1,y1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值