标题:整理玩具
小明有一套玩具,一共包含NxM个部件。这些部件摆放在一个包含NxM个小格子的玩具盒中,每个小格子中恰好摆放一个部件。
每一个部件上标记有一个0~9的整数,有可能有多个部件标记相同的整数。
小明对玩具的摆放有特殊的要求:标记相同整数的部件必须摆在一起,组成一个矩形形状。
如以下摆放是满足要求的:
00022
00033
44444
12244
12244
12233
01234
56789
以下摆放不满足要求:
11122
11122
33311
111111
122221
122221
111111
11122
11113
33333
给出一种摆放方式,请你判断是否符合小明的要求。
输入
输入包含多组数据。
第一行包含一个整数T,代表数据组数。 (1 <= T <= 10)
以下包含T组数据。
每组数据第一行包含两个整数N和M。 (1 <= N, M <= 10)
以下包含N行M列的矩阵,代表摆放方式。
输出
对于每组数据,输出YES或者NO代表是否符合小明的要求。
【样例输入】
3
3 5
00022
00033
44444
3 5
11122
11122
33311
2 5
01234
56789
【样例输出】
YES
NO
YES
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
==============================
思路:
两种策略:
- 遍历时候计算每个区间的最大长宽下的起点以及终点坐标,然后跟其他区间比较判断是否重合(重合即:有别的玩具混入区间)
计算最大长宽下的两个坐标->遍历所有玩具(好在最大数据规模NM<=10,可行) - 遍历时候计算每个区间的外边的起点和终点坐标,判断这个区间是否存在别的玩具(其终点坐标也是下一个遍历的区间的起点坐标)
遍历下一个区间的外边长宽(未知区间数量)->dfs
结论
运行的效率前者优于后者
原因:
- 第二种策略没有利用本题数据规模NM较小的条件,使用dfs搜索(基于区间数量未知的局面,这么做是必然的)
- 从具体的实现代码来看,第二种方法基于对未知区间的遍历,使得我不得不将下面的这种需要排除的局面考虑在内(使用一个数组去将出现过的数字计入),代码在实现的时候虽然不长但是类似的逻辑判断比较多,比较繁琐,第一种方法使用全集遍历,则没有边界未知的情况
第一种策略:区间重复判断
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n =sc.nextInt();
String[] ans =new String[n]; //单独做一个数组打印结果,避免输出结果和输入字符在一块显示
char[][] a =null;
int width =0 ,higth =0;
for(int i =0 ;i <n ;i ++) {
higth =sc.nextInt();
width =sc.nextInt();
//记录数字出现
boolean[] isIn =new boolean[10];
//记录最大长宽
int[][] sta_node =new int[10][2];
int[][] end_node =new int[10][2];
//一个一个的扫描
a =new char[higth][];
int val =0;
for(int y =0 ;y <higth ;y ++) {
a[y] =sc.next().toCharArray();
for(int x =0 ;x <width ;x ++) {
val =a[y][x] -48;
//初始坐标
if(!isIn[val]) {
isIn[val] =true;
end_node[val][0] =sta_node[val][0] =x;
end_node[val][1] =sta_node[val][1] =y;
continue;
}
//边界坐标
end_node[val][0] =x;
end_node[val][1] =y;
}
}
//找重叠
boolean x_in =false ,y_in =false ,in =false;
out:for(int j =0 ;j <=9 ;j ++) {
if(!isIn[j]) continue; //数字没有出现过
for(int k =j +1 ;k <=9 ;k ++) {
if(!isIn[k]) continue;
//重叠的逻辑判断有点复杂(j/k可以倒置)
x_in =end_node[j][0] >=sta_node[k][0] &&sta_node[j][0] <=end_node[k][0];
y_in =end_node[j][1] >=sta_node[k][1] &&sta_node[j][1] <=end_node[k][1];
if(x_in &&y_in) {in =true; break out;}
}
}
if(in) ans[i] ="NO"; else ans[i] ="YES";
}
sc.close();
for(String s :ans) System.out.println(s);
}
}
第二种策略:dfs摸索边长
值得吐槽的是:使用了好多数组,逻辑复杂了
(当时我自己的第一种实现的想法)
public class dfs_整理玩具_4 {
static char[][][] c;
static boolean[] b;
static boolean[][][] isPlaced;
static long t;
public static void main(String[] args) {
init();
for(int n =0 ;n <c.length ;n ++) {
b =new boolean[10];
isPlaced[n][0][0] =true;
if(dfs(c[n][0][0] ,0 ,0 ,n)) System.out.println("YES"); else System.out.println("NO");
}
System.out.println(System.currentTimeMillis() -t);
}
/**
* @param ele 正在遍历的元素
* @param y
* @param x
* @param n 正在遍历的区块
* @return 该区块是否符合要求
*/
private static boolean dfs(char ele, int y, int x ,int n) {
int y_tmp =c[n].length -1 ,x_tmp =c[n][0].length -1;
for(int i =x +1 ;i <c[n][0].length ;i ++) {
x_tmp=i;
if(ele !=c[n][y][i]) {
x_tmp --;
if(!isPlaced[n][y][i]) if(!dfs(c[n][y][i] ,y ,i ,n)) return false;
break;
}
}
for(int i =y +1 ;i <c[n].length ;i ++) {
y_tmp =i;
if(ele !=c[n][i][x]) {
y_tmp --;
//(x <1 ||isPlaced[n][i][x -1]) -> 左侧同元素是否未遍历 这个感觉很蠢
if(!isPlaced[n][i][x] &&(x <1 ||isPlaced[n][i][x -1])) if(!dfs(c[n][i][x] ,i ,x ,n)) return false;
break;
}
}
if(!check(c[n][y][x] ,y ,x ,y_tmp ,x_tmp ,n)) return false; b[c[n][y_tmp][x_tmp] -48] =true;
return true;
}
/**
* @param ele
* @param sta_y
* @param sta_x
* @param end_y
* @param end_x
* @param n
* @return
*/
private static boolean check(char ele, int sta_y, int sta_x, int end_y, int end_x, int n) {
if(b[ele -48]) return false;
for(int i =sta_x ;i <=end_x ;i ++) for(int j =sta_y ;j <=end_y ;j ++) { if(c[n][j][i] !=ele) return false; isPlaced[n][j][i] =true;}
return true;
}
private static void init() {
Scanner sc = new Scanner(System.in);
int n =sc.nextInt();
t =System.currentTimeMillis();
c =new char[n][][];
isPlaced =new boolean[n][][];
int wid =0, hig =0;
for(int i =0 ;i <n ;i ++) {
hig =sc.nextInt();
wid =sc.nextInt();
c[i] =new char[hig][wid];
isPlaced[i] =new boolean[hig][wid];
for(int h =0 ;h <hig ;h ++) c[i][h] =sc.next().trim().toCharArray();
}
sc.close();
}
}