[USACO2.1.1]The Castle——Java

题目描述

城堡有多少个房间,每个房间有多大。要把一面单独的墙(指两个单位间的墙)拆掉以形成一个更大的房间。 你的工作就是算出房间数与房间的大小。

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

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

友情提示,这个城堡的平面图是7×4个单位的。一个“房间”的是平面图中一个由“#”、“-”、“|”围成的格子(就是图里面的那一个个的格子)。比如说这个样例就有5个房间。(大小分别为9、7、3、1、8个单位(排名不分先后))。移去箭头所指的那面墙,可以使2个房间合为一个新房间,且比移去其他墙所形成的房间都大。

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

输入格式

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

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

1: 在西面有墙 0001

2: 在北面有墙 0010

4: 在东面有墙 0100

8: 在南面有墙 1000

输出格式

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

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

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

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

选择最佳的墙来推倒。有多解时选最靠西的,仍然有多解时选最靠南的。同一格子北边的墙比东边的墙更优先。
用该墙的南邻单位的北墙或西邻单位的东墙来表示这面墙,方法是输出邻近单位的行数、列数和墙的方位(“N”(北)或者"E"(东))。

输入输出样例

输入样例

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

输出样例

5
9
16
4 1 E

Java代码

package Test;
import java.util.Scanner;
public class Test22 {
	private static int N,M;
	private static int[][]map=null;
	private static boolean[][]visit=null;
	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		N=in.nextInt();
		M=in.nextInt();
		map=new int[M][N];
		visit=new boolean[M][N];
		int max=0; // 最大房间
		int num=0; // 房间数
		for(int i=0;i<M;i++) {
			for(int j=0;j<N;j++) {
				map[i][j]=in.nextInt();
			}
		}
		visitReset(); // 重置visit标志
		for(int i=0;i<M;i++) {
			for(int j=0;j<N;j++) {
				if(visit[i][j]==false) {
					int t=DFS(i,j);
					max = (t>max?t:max);
					num++;
				}
			}
		}
		System.out.println(num);
		System.out.println(max);
		visitReset(); // 重置visit标志
		int sumMax=0,row=0,col=0;
		char dir='N';
		for(int j=0;j<N;j++){  // 先考虑西
			for(int i=M-1;i>=0;i--) { // 再考虑南
				if(visit[i][j]==false) {
					int t1=DFS(i,j);
					if((map[i][j]&2)!=0) { // 考虑北
						int t2=DFS(i-1,j);
						if(t1+t2>sumMax) { // 再考虑东
							sumMax=t1+t2;
							row=i+1;
							col=j+1;
							dir='N';
						}
					}
					if((map[i][j]&4)!=0) {
						int t2=DFS(i,j+1);
						if(t1+t2>sumMax) {
							sumMax=t1+t2;
							row=i+1;
							col=j+1;
							dir='E';
						}
					}
				}
				visitReset(); // 重置visit标志
			}
		}
		System.out.println(sumMax);
		System.out.println(row+" "+col+" "+dir);
		in.close();
	}
	
	private static void visitReset() {
		for(int i=0;i<M;i++) {
			for(int j=0;j<N;j++) {
				visit[i][j]=false;
			}
		}
	}
	
	private static int DFS(int row, int col) {
		if(row>N-1 || row<0 || col>N-1 || col<0 || visit[row][col]==true) return 0;
		visit[row][col]=true;
		int count=1; // 调用递归的次数,下面的判断方法源自网络(比自己的判断二进制聪明多了) 
		if((map[row][col]&1)==0) count+=DFS(row,col-1); // 西
		if((map[row][col]&2)==0) count+=DFS(row-1,col); // 北
		if((map[row][col]&4)==0) count+=DFS(row,col+1); // 东
		if((map[row][col]&8)==0) count+=DFS(row+1,col); // 南
		return count;
	}
}

学习链接

  1. https://www.cnblogs.com/lxtx/p/6933091.html?utm_source=itdadao&utm_medium=referral
  2. https://www.jlqwer.com/posts/4689.html
  3. https://blog.csdn.net/weixin_43909855/article/details/85343687
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值