前言
原题链接: 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的方格是不是也全都适应,这还是利用上班摸鱼的时间来写的。不说了,下午还要上班,这几天中午就没休息过。