Java算法篇【剪格子】


前言

原题链接: 1206. 剪格子


一、题目解析

在所有解中,包含左上角的分割区可能包含的最小的格子数目。

也就是说只要考虑从左上角开始剪的情况
这里采用的是以坐标轴的方式解题的
具体如下:

在这里插入图片描述
从左上角的(0,0)开始以横坐标+1或纵坐标+1来移动

沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是 60。

只要保持可移动的状态下累计达到总数的一半且判断另一部分是否也连通即可
而另一部分的判断可用每个位置的相邻个数是否在1个以上,
且最多只允许有2个相邻个数为1的
判断是否相邻则是判断是否横坐标+1-1或纵坐标+1-1

二、代码编写

/**
 * @author: ljp
 * @description: 剪格子
 * @date: 2023年1月5日 上午10:28:23
 */
public class CutLattice {

	/** 方格数据 */
	private static int[] DATA;
	/** 方格对应坐标 */
	private static int[][] COORD;
	/** x=每行个数y=行数 */
	private static int X, Y;
	/** 结果集 */
	private static String[] RESULT = new String[20];
	/** 结果长度 */
	private static int LEN = 0;

	public static void main(String[] args) {
		// 平均值
		int v = 0;
		// 方格(用户输入)
		int m = 3, n = 3;
		CutLattice.X = m;
		CutLattice.Y = n;
		int sum = 0;
		int result = 0;
		// 用户输入(从左往右,从上往下)
		int[] p = { 1, 1, 1, 2, 1, 1, 1, 1, 1 };
		CutLattice.DATA = p;
		for (int i = 0; i < p.length; i++) {
			sum += p[i];
		}
		if (sum % 2 > 0) {
			System.out.println(result);
			return;
		}
		v = sum / 2;
		// 1.坐标映射(左上角开始-0号位纵坐标1号位横坐标)
		int[][] coordinate = new int[p.length][2];
		for (int i = 0, index = 0; i < n; i++) {
			for (int j = 0; j < m; j++, index++) {
				coordinate[index][0] = i;
				coordinate[index][1] = j;
			}
		}
		// 验证坐标
//		for(int i=0;i<coordinate.length;i++) {
//			System.out.println(i+"的坐标为:"+coordinate[i][0]+","+coordinate[i][1]);
//		}
		CutLattice.COORD = coordinate;
		// 2.相邻位置逐个累加
		boolean[] off = new boolean[p.length];
		off[0] = true;
		accrual(0, p[0], v - p[0], off);
		for (int i = 0; i < CutLattice.LEN; i++) {
			// 3.判断剩余部分是否连通
			boolean isConnected = isConnected(CutLattice.RESULT[i]);
			if (isConnected) {
				int len = CutLattice.RESULT[i].split(",").length;
				result = result == 0 ? len : result > len ? len : result;
			}
			System.out.println(CutLattice.RESULT[i] + "======" + (isConnected ? "剩余部分连通" : "剩余部分不连通"));
		}
		// 输出结果
		System.out.println(result);

	}

	/**
	 * 相邻位置逐个累加
	 * 
	 * @param index  开始位置
	 * @param total  已经累加数量
	 * @param target 剩余累加数量
	 * @param data   保存结果用数组
	 */
	private static void accrual(int index, int total, int target, boolean[] off) {
		if (target < 0) {
			return;
		}
		if (target == 0) {
			String data = "";
			// 保存data
			for (int i = 0; i < off.length; i++) {
				data += (off[i] ? "-" + i + "," : "");
			}
			if (!isRepeat(data)) {
				CutLattice.RESULT[CutLattice.LEN] = data;
				CutLattice.LEN++;
			}
			return;
		}
		// 递归四种情况
		// 纵坐标
		int y = CutLattice.COORD[index][0];
		// 横坐标
		int x = CutLattice.COORD[index][1];
		// 公式:下标 = 纵坐标*每行个数+横坐标
		// 1.向下(纵坐标+1)
		int yUpIndex = (y + 1) * CutLattice.X + x;
		if (y + 1 < CutLattice.Y && !off[yUpIndex]) {
			off[yUpIndex] = true;
			accrual(yUpIndex, total + CutLattice.DATA[yUpIndex], target - CutLattice.DATA[yUpIndex], off);
			off[yUpIndex] = false;
		}
		// 2.向上(纵坐标-1)
		int yDoIndex = (y - 1) * CutLattice.X + x;
		if (y > 0 && !off[yDoIndex]) {
			off[yDoIndex] = true;
			accrual(yDoIndex, total + CutLattice.DATA[yDoIndex], target - CutLattice.DATA[yDoIndex], off);
			off[yDoIndex] = false;
		}
		// 3.向右(横坐标+1)
		int xUpIndex = y * CutLattice.X + x + 1;
		if (x + 1 < CutLattice.X && !off[xUpIndex]) {
			off[xUpIndex] = true;
			accrual(xUpIndex, total + CutLattice.DATA[xUpIndex], target - CutLattice.DATA[xUpIndex], off);
			off[xUpIndex] = false;
		}
		// 4.向左(横坐标-1)
		int xDoIndex = y * CutLattice.X + x - 1;
		if (x > 0 && !off[xDoIndex]) {
			off[xDoIndex] = true;
			accrual(xDoIndex, total + CutLattice.DATA[xDoIndex], target - CutLattice.DATA[xDoIndex], off);
			off[xDoIndex] = false;
		}
		off[index] = false;
	}

	/**
	 * 结果去重
	 */
	private static boolean isRepeat(String data) {
		for (int i = 0; i < CutLattice.LEN; i++) {
			if (CutLattice.RESULT[i].equals(data)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 剩余部分是否连通
	 * 
	 * @return
	 */
	private static boolean isConnected(String data) {
		int length = DATA.length - data.split(",").length;
		if (length == 1) {
			return true;
		}
		// 获取剩余部分数组
		int[] surplus = new int[length];
		for (int i = 0, len = 0; i < CutLattice.DATA.length; i++) {
			if (!data.contains("-" + i + ",")) {
				surplus[len] = i;
				len++;
			}
		}
		// 存储每个位置的相邻位置个数
		int[] number = new int[surplus.length];
		for (int i = 0; i < surplus.length - 1; i++) {
			for (int n = i + 1; n < surplus.length; n++) {
				// 判断坐标是否相邻
				int iy = CutLattice.COORD[surplus[i]][0];
				int ix = CutLattice.COORD[surplus[i]][1];
				int ny = CutLattice.COORD[surplus[n]][0];
				int nx = CutLattice.COORD[surplus[n]][1];
				if (iy == ny && (ix - nx == -1 || ix - nx == 1)) {
					number[i]++;
					number[n]++;
				} else if (ix == nx && (iy - ny == -1 || iy - ny == 1)) {
					number[i]++;
					number[n]++;
				} else {
					continue;
				}
			}
		}
		// 找出相邻个数小于2的(不能超过2个)
		int count = 0;
		for (int n : number) {
			if (n < 2) {
				count++;
			}
		}
		return count < 3;
	}

}

三、结果分析

-0,-3,-6,-7,======剩余部分连通
-0,-3,-4,-7,======剩余部分不连通
-0,-1,-3,-4,======剩余部分连通
-0,-3,-4,-5,======剩余部分不连通
-0,-1,-4,-7,-8,======剩余部分不连通
-0,-1,-4,-6,-7,======剩余部分不连通
-0,-1,-4,-5,-8,======剩余部分不连通
-0,-1,-2,-4,-5,======剩余部分连通
-0,-1,-2,-5,-8,======剩余部分连通
4

程序输出为数组下标
结果参考图:
在这里插入图片描述

总结

以上就是今天讲的内容,这是第一次接触蓝桥杯的算法题,解开来还有点小激动。因为没经过多少测试,也不知道非3*3的方格是不是也全都适应,这还是利用上班摸鱼的时间来写的。不说了,下午还要上班,这几天中午就没休息过。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值