dfs---------------------深度优先搜索

本文通过两个具体案例介绍深度优先搜索(DFS)的应用方法:一是寻找油田区块数量问题,二是解决质数环问题。详细解释了如何使用递归实现DFS算法,并提供了完整的AC代码。

            深度优先搜索就是不断地重复深入的过程直到找到你需要结果或者越界为止

通常的方法就是把每一种可能都期尝试一遍(一般用for循环遍历)。当前这一步解决之后便进入下一步dfs(step+1)。

下一步的解决方案是完全一样的。下面给出基本模型

void dfs(int step)
{
    判断边界
    尝试每一种可能 for(i=1;i<=n;i++)
    {
         继续下一步 dfs(step+1);   
    }
    返回
}

            实现方法

         DFS一般用递归来实现,改变当层状态不断深入,直到找到答案或者已经可以知道这样下去无法得到答案,再返回到上一个状态(恢复该层状态)继续递归。保证每一个点(每一种可能性)都遍历过,但是并不能保证答案是最优解(如最小值,最短路等,这些一般用BFS实现)。

                                                                                                                                                                                                                     如图,在这棵树上做dfs为 1 2 4 5 3 6 7        

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

下面我举几个栗子

1.

A - Oil Deposits

 POJ - 1562 

The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.

Input

The input contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either `*', representing the absence of oil, or `@', representing an oil pocket. 
 

Output

are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.

Sample Input

1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5 
****@
*@@*@
*@**@
@@@*@
@@**@
0 0

Sample Output

0
1
2
2

题目是英文的但是意思还是好懂的

   有一片区域,人为的给他划分成若干块小区域,如果有石油我们给这个·小区域标上@,如果没有,标上*;

不论是横的竖的斜的,只要两块小区域连在一起就可以认为他们属于同一片油田。题目就是要我们统计有多少块油田

 思路

从头开始找,找到一块就搜溹他的八个方向,找到所有能找到的油田并打上标记,这样我们称为一趟

我们只要记录走了几趟就好了;

AC代码

#include<iostream> 
#include<cstdio>
#include<algorithm>
using namespace std;
int xy[8][2]={1,0,1,-1,1,1,0,1,0,-1,-1,0,-1,1,-1,-1}; //八个方向。
char s[110][110];
int ans,m,n;
void dfs(int x,int y){
	s[x][y] = '*';             // 将@变为*
	for(int i = 0;i < 8; i++){
		int a = x + xy[i][0];
		int b = y + xy[i][1];
		if(a < m && a >= 0 && b < n && b >= 0 && s[a][b] == '@')
				dfs(a,b);
	}
	return;                        
}
int main(){
	while(cin >> m >> n && n && m){
		ans = 0;
		for(int  i = 0;i < m; i++)
			scanf("%s",s[i]);
		for(int i = 0; i < m;i++)
			for(int j = 0; j < n;j++){//遍历每个点
				if(s[i][j] == '@'){//判断该点是不是@,如果是的话,dfs。
					dfs(i,j);
					ans++;
				}
			} 
		cout << ans<<endl;
	}
	return 0;
}

例二

D - Prime Ring Problem

 HDU - 1016 

A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime. 

Note: the number of first circle should always be 1. 

 

Input

n (0 < n < 20). 

Output

The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order. 

You are to write a program that completes above process. 

Print a blank line after each case. 

Sample Input

6
8

Sample Output

Case 1:
1 4 3 2 5 6
1 6 5 2 3 4

Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2

题意

这个题就一个全排列的问题

只不过对排列的顺序有要求而已

就是相邻两个数相加为素数

AC代码

#include <bits/stdc++.h>

using namespace std;
int n;
struct node
{
	int mark;
	int num;
}stu[25];
int prime[12]={2,3,5,7,11,13,17,19,23,29,31,37};

int  dfs(int k)
{
	int flag;
	int i;
	if(k==n+1)
	{
		for(i=0;i<12;i++)
		{
			if((stu[k-1].num+1)==prime[i])
			{
				for(int j=1;j<n;j++)
					printf("%d ",stu[j].num);
				    printf("%d\n",stu[n].num);
			}
		 } 
		
	}
	else
	{
		for(i=2;i<=n;i++)
		{
			flag=0;
			for(int j=0;j<12;j++)
			{
				if((i+stu[k-1].num)==prime[j])
				flag=1;
			}
			if(stu[i].mark&&flag)
			{
				stu[i].mark=0;
				stu[k].num=i;
				dfs(k+1);
				stu[i].mark=1;
			}
		}
		
	 } 
	return 0;
}



int main()
{  
	int Case=1;
	while(cin>>n)
	{
		printf("Case %d:\n",Case++);
	    if(n==1)
	    {
	    	printf("1\n\n");
	    	continue;
		}
		
		stu[1].mark=0;
		for(int i=2;i<=n;i++)
            stu[i].mark=1;
		stu[1].num=1;
		dfs(2);
		printf("\n");
			
 	}	 
	return 0;
}

 

                                                        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值