利用算法dfs解决的问题

一、树的遍历
二、图的遍历
例题:危险系数

/*
这道题可以用dfs来解决。如果从a到b可走的n条路中,其中某个点出现了n次,则这个点就是割点,去掉它则不通。
从a到b有n种方法,则n种方法都路过的点就是关键点 
*/ 
#include<stdio.h>
#include<string.h>
int graph[1005][1005];
int visited[1005];
int n;
int times[1005];
int ans=0;
void dfs(int x,int y){
	int i;
	visited[x]=1;
	if(x==y){
		ans++;
		for(i=1;i<=n;i++){
			if(visited[i]==1)
			    times[i]++;
		}
	}
	else{
		for(i=1;i<=n;i++){
			if((graph[x][i]!=0)&&(visited[i]==0)){
				dfs(i,y);
				visited[i]=0;
			}
		}
	}
}
int main(){
	int m;
	int i;
	int x,y;
	int count=0;
	scanf("%d %d",&n,&m);
	memset(graph,0,sizeof(graph));
	memset(visited,0,sizeof(visited));
	memset(times,0,sizeof(times));
	for(i=1;i<=m;i++){
		scanf("%d %d",&x,&y);
		graph[x][y]=1;
		graph[y][x]=1;
	}
	scanf("%d %d",&x,&y);
	dfs(x,y);
	for(i=1;i<=n;i++){
		if(ans==times[i])
		    count++;
	} 
	//因为x和y也算进来,故要减掉 
	if(ans==0){
		printf("-1");
	}else{
		printf("%d",count-2);
	} 
	
	return 0;
} 

三、固定节点遍历矩阵
例题:剪格子

/*
回溯法 
dfs上下左右都要走,如果走过就记录下来 
走步数,走的值 
回溯前加,则回溯后减 
该回溯需要回溯的值,1、是否走过,2、所走步数,3、所走值 

注意该题是先输入列,再输入行 

方法:
就是确定结束条件
dsf遍历上下左右,却判断是否已经走了和越界
走一个方向时,要确定走直接要加什么,然后走结束后要减掉之前加的 
*/ 
#include<stdio.h>
#include<string.h>
int matrix[15][15];
int record[15][15];
int sum=0;
int n,m;
int count=0x3f3f3f3f;
int strcount=0;
int strsum=0;
//减少代码 
int nextt[4][4]={{0,1},{1,0},{0,-1},{-1,0}};
void recall(int x,int y){
	//判断是否相等,是则退出 
	if(strsum==sum-strsum){
		if(strcount<count)
		   count=strcount;
		return ;
	}
	else{
		int i;
		for(i=0;i<4;i++){
			int xx=nextt[i][0]+x;
			int yy=nextt[i][1]+y;
			//越界判断 
			if(xx<0||xx>=n||yy<0||yy>=m)
			    continue;
			    //是否遍历过判断 
			if(!record[xx][yy]){
				record[xx][yy]=1;
				strcount++;
				strsum+=matrix[xx][yy];
				recall(xx,yy);
				strsum-=matrix[xx][yy];
				strcount--;
				record[xx][yy]=0;
			}
		}
		
//		//走上 
//       if(x-1>=0&&x-1<n&&record[x-1][y]==0){
//	        record[x-1][y]=1;
//			strcount++;
//		    strsum+=matrix[x-1][y];
//			recall(x-1,y);
//			record[x-1][y]=0;
//			strcount--;
//		    strsum-=matrix[x-1][y];
//		}
//		//走下 
//		if(x+1>=0&&x+1<n&&record[x+1][y]==0){
//			record[x+1][y]=1;
//			strcount++;
//		    strsum+=matrix[x+1][y];
//			recall(x+1,y);
//			record[x+1][y]=0;
//			strcount--;
//		    strsum-=matrix[x+1][y];
//		}
//	    //走左 
//		if(y-1>=0&&y-1<m&&record[x][y-1]==0){
//			record[x][y-1]=1;
//			strcount++;
//		    strsum+=matrix[x][y-1];
//			recall(x,y-1);
//			record[x][y-1]=0;
//			strcount--;
//		    strsum-=matrix[x][y-1];
//		}
//        //走右 
//		if(y+1>=0&&y+1<m&&record[x][y+1]==0){
//			record[x][y+1]=1;
//			strcount++;
//		    strsum+=matrix[x][y+1];
//			recall(x,y+1);
//			record[x][y+1]=0;
//			strcount--;
//		    strsum-=matrix[x][y+1];
//		}
	} 
}
int main(){
	int i,j;
	scanf("%d%d",&m,&n);
	for(i=0;i<n;i++){
		for(j=0;j<m;j++){
		 	scanf("%d",&matrix[i][j]);
		    sum+=matrix[i][j];
		}
	}
	if(sum%2!=0){
		printf("0");
	}else{
	    memset(record,0,sizeof(record));
	    strcount++;
    	strsum+=matrix[0][0];
    	record[0][0]=1; 
    	recall(0,0);
     	if(count==0x3f3f3f3f){
		    printf("0");
    	}else{
     		printf("%d",count);	
    	}	
	} 
	return 0;
}

四、不固定节点遍历矩阵
例题:剪邮票

#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;	   
} 

五、方格以点作区分,而不是以单元格
例题:方格分割

#include<stdio.h>
#define  N 6
int next[4][2]={{0,-1},{0,1},{-1,0},{1,0}};
int matrix[7][7];
int count=0;
void dfs(int x,int y){
	int i;
	int xx;
	int yy;
	if(x<=0||y<=0||x>=N||y>=N){
		count++;
	}else{
		for(i=0;i<4;i++){
		    xx=next[i][0]+x;
		    yy=next[i][1]+y;
		    if(matrix[xx][yy]!=1){
		    	matrix[xx][yy]=1;
		    	matrix[6-xx][6-yy]=1;
		    	dfs(xx,yy);
		    	matrix[xx][yy]=0;
		    	matrix[6-xx][6-yy]=0;
			}
		}
	}
}
int main(){
	matrix[N/2][N/2]=1;
	dfs(N/2,N/2);
	printf("%d",count/4);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值