一、图的直接遍历
二、正方形或者长方形的要标记
三、利用dsf判断图是否连通
注意:返回条件不好,容易溢出
例如:if(grid[i][j]!=1||i<0||i>=n||j<0||j>=m)这样会导致溢出
正确if(i<0||i>=n||j<0||j>=m||grid[i][j]!=1)先判断是否过界了,才判断数组
例题:
#include<stdio.h>
void dsf(int a[3][4],int p,int q){
a[p][q]=0;
if(p<2&&a[p+1][q]==1) dsf(a,p+1,q); //下方
if(p>0&&a[p-1][q]==1) dsf(a,p-1,q); //上方
if(q>0&&a[p][q-1]==1) dsf(a,p,q-1); //左方
if(p<3&&a[p][q+1]==1) dsf(a,p,q+1); //右方
return;
}
int main(){
int a[3][4]{{0,0,0,0},{1,1,0,0},{1,0,0,0}}; //图
int cnt=0; //连同个数
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
if(a[i][j]==1){
dsf(a,i,j);
cnt++;
}
}
}
printf("%d",cnt);
return 0;
}
四、dsf不能用于T字形搜索
例题
第七题:剪邮票
有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
代码
#include<stdio.h>
//116
int sum;
int isOK(int a[],int n,int m){ //判断全排列是否重复
if(m>n){
for(;n<m;n++){
if(a[n]==a[m])
return false;
}
}
return true;
}
void swap(int *i,int *j){ //两数交换
int n=*i;
*i=*j;
*j=n;
return;
}
void dsf(int b[3][4],int p,int q){ //dsf找连同数
b[p][q]=0;
if(p>0&&b[p-1][q]==1) dsf(b,p-1,q);
if(p<2&&b[p+1][q]==1) dsf(b,p+1,q);
if(q>0&&b[p][q-1]==1) dsf(b,p,q-1);
if(q<3&&b[p][q+1]==1) dsf(b,p,q+1);
return;
}
int check(int a[]){ //判断5个数字是否相连
int b[3][4];
int cnt=0;
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
b[i][j]=a[i*4+j];
}
}
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
if(b[i][j]==1){
dsf(b,i,j);
cnt++;
}
}
}
return cnt==1;
}
void perm(int a[],int p,int q){ // 全排列
if(p==q){
if(check(a))
sum++;
}
else{
for(int i=p;i<=q;i++){
if(isOK(a,p,i))
{
swap(&a[i],&a[p]);
perm(a,p+1,q);
swap(&a[i],&a[p]);
}
}
}
}
int main(){
sum=0;
int a[12]={0,0,0,0,0,0,0,1,1,1,1,1};
perm(a,0,11);
printf("%d",sum);
return 0;
}