有关矩阵(图形)遍历问题的总结

将用三种遍历矩阵的例子对dfs算法特性进行分析解释
1.岛屿面积问题
2.矩阵分割(中心对称)
3.一般意义的矩阵分割

一、岛屿面积问题
给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合。你可以假设二维矩阵的四个边缘都被水包围着。找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为0。)
无论是求出最大岛屿面积还是求出所有岛屿个数解法大体一致核心代码如下

public static int dfs(int x,int y,char[][] map) {
if(x<0||y<0||x>=map.length||y>=map[0].length||map[x][y]==‘0’) {
return count;
}
map[x][y]=‘0’;
count++;
dfs(x-1,y,map);
dfs(x,y+1,map);
dfs(x+1,y,map);
dfs(x,y-1,map);
return count;
}

其寻找方式取决于题目对于连通性的定义是上下左右4个方向还是加上了2组对角的8个方向,对于遍历过的位置重新进行赋值可大大减少递归次数。
二、矩阵分割问题(蓝桥17省赛)
沿着格子的边线裁剪成2部分要求2部分完全相同问共有多少种裁剪方式
在这里插入图片描述
此题的题眼在于2部分完全相同让人联想到八卦的中心对称那么下面的问题则变成了如何用矩阵的形式来表示中心对称以及如何遍历出所有中心对称图形。分开考虑的确很复杂,但是由于中心对称的特性,中心点就变得十分特殊而重要,我们其实只需要从中心点向外部边界中心对称的进行扩散遍历即可达到要求


public class S20174 {
 static int map[][]=new int[7][7];
 static int a[][]= {{-1,0},{1,0},{0,-1},{0,1}};
 static int count=0;
public static void main(String[] args) {
 map[3][3]=1;//细节1需要将起点初始化
 dfs(3,3);
 System.out.println(count/4);//细节二需注意旋转所得方法相同
}
public static void dfs(int x,int y) {
 if(x==0||y==0||x==6||y==6) {
  count++;
  return;
 }
 for(int i=0;i<4;i++) {
  int nx=x+a[i][0];
  int ny=y+a[i][1];
  if(nx>=0&&nx<=6&&ny>=0&&ny<=6&&map[nx][ny]==0) {
   map[nx][ny]=1;
   map[6-nx][6-ny]=1;
   dfs(nx,ny);
   map[nx][ny]=0;
   map[6-nx][6-ny]=0;
  }
 }
}
}

三、剪邮票问题(2016蓝桥杯第7题)
有12张连在一起的12生肖的邮票。现在你要从中剪下5张来,要求必须是连着的(仅仅连接一个角不算相连)
本题单纯用深度优先遍历是无法得到所有结果的原因是深度优先遍历虽可遍历得到矩阵的每一个点但是无法得到各个点组合你无论从哪个起点遍历(矩阵初始化各点为0)也无法得到如下的图形(你如果非要杠其实也行,但你懂我意思吧)这是由于深度遍历的特性所决定的,只可将当前路径走到底才会回溯到上一步
0 1 0 0
1 1 1 0
0 1 0 0

这里的代码我写的确实比较麻烦而且暴力
思路是需先产生所有排列再判断排列是否符合条件,要注意不可重复计算


public class S20167 {
 //先产生5个数字然后判断是否相连
 static int a[]=new int[5];
 static boolean isvisit[]=new boolean[12];
 static int count=0;
 static int count2=0;
public static void main(String[] args) {
 dfs(0);
 System.out.println(count2/120);
}
public static void dfs(int n) {
 if(n==5) {
  if(check()) {
   count2++;
  }
  return;
 }
 for(int i=1;i<=12;i++) {
  if(isvisit[i-1]==false) {
   isvisit[i-1]=true;
   a[n]=i;
   dfs(n+1);
   isvisit[i-1]=false;
  }
 }
}
public static boolean check() {
 int c2=0;
 int c=1;
 int a = 0,b=0;
 int map[][]=new int[3][4];
 for(int i=0;i<3;i++) {
  for(int j=0;j<4;j++) {
   map[i][j]=c;
   c++;
  }
 }
 for(int i=0;i<3;i++) {
  for(int j=0;j<4;j++) {
   if(isvisit[map[i][j]-1]==true) {
    map[i][j]=0;
    a=i;
    b=j;
   }
  }
 }
 dfs2(a,b,map);
 if(count!=5) {
  count=0;
  return false;
 }else {
  count=0;
  return true;
 }
}
public static int dfs2(int x,int y,int [][]map) {
 if(x<0||y<0||x>=3||y>=4||map[x][y]!=0) {
  return count;
 }
 count++;
 map[x][y]=-1;
 dfs2(x-1,y,map);
 dfs2(x,y+1,map);
 dfs2(x+1,y,map);
 dfs2(x,y-1,map);
 return count;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值