DFS深度优先搜索算法

例题一:

题目来源:POJ-3620:Avoid The Lakes

题目大意:约翰的农场被暴风雨给淹没了,损失很大,他的保险公司将支付给他,但是支付金额取决于被淹没的最大面积。这个农场是一个边长分别为n、m的矩形,包含nm个空间,每个空间要么是干的,要么是被淹没的,一共有k个空间被淹没。求最大的淹没面积。

题目分析:首先建立坐标,标记被淹没的空间,然后从左上角搜索被淹没的空间,并取消标记,再以此为中心向四周搜索是否有被淹没的空间,有的话继续计数并取消标记,以此类推,找出所有被淹没的空间,最后排序,找到被淹没最大的面积,(考查深度优先搜索)。

AC代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int a[110][110];
int num[110];
int ans,n,m;
void dfs(int x,int y)		//深度优先搜索 
{
	if(a[x][y]==1||x<1||x>n||y<1||y>m)		//判断是否越界,是否是被淹没的 
		return ;
	num[ans]++;		//计数 
	a[x][y]=1;
	dfs(x-1,y);
	dfs(x+1,y);
	dfs(x,y+1);
	dfs(x,y-1);
}
int main()
{
	int i,j,k,x,y;
	while(~scanf("%d%d%d",&n,&m,&k))
	{
		ans=-1;
		memset(num,0,sizeof(num));		//初始化 
		for(i=1;i<=n;i++)		//建立坐标 
			for(j=1;j<=m;j++)
				a[i][j]=1;
		while(k--)
		{
			scanf("%d%d",&x,&y);		//标记被淹没的 
			a[x][y]=0;
		}
		for(i=1;i<=n;i++)
			for(j=1;j<=m;j++)
			{
				if(a[i][j]==0)		//搜索被淹没的 
				{
					ans++;
					dfs(i,j);
				}
			}
		sort(num,num+ans+1);		//快排 
		printf("%d\n",num[ans]);
	}
	return 0;
}

例题二:

题目来源:ZOJ-2100:Seeding

题目大意:春天来了,汤姆有一块包含n*m个方块良田,他有一个耕种机器(位于左上角),但是其中有一些方块田地有大石块,机器不能通过,然而他想把没有石块的全部良田耕种,可能吗?

题目分析:首先利用字符串建立地图,找出所以有石块的田地并计数,然后从左上角搜索没有石块的良田并标记计数,然后判断下一块田地是否可以耕种,以此类推,直到不能再耕种,判断所记的数目是否等于所有田地的总数目,(考查深度优先搜索)。

AC代码:

#include <stdio.h>
#include <string.h>

char str[10][10];
int n,m,sum;
bool flag;

void dfs(int x,int y)		//深度优先搜索 
{
	if(x<0||x>n-1||y<0||y>m-1||str[x][y]=='S')		//排除不符合条件的 
		return ;
	sum++;
	str[x][y]='S';		//标记 
	if(sum==n*m)		//判断是否可以全部耕种 
	{
		flag=true;
		return ;
	}
	dfs(x-1,y);
	dfs(x+1,y);
	dfs(x,y-1);
	dfs(x,y+1);
	sum--;
	str[x][y]='.';
}

int main()
{
	int i,j;
	while(scanf("%d%d",&n,&m),n||m)
	{
		sum=0;
		flag=false;
		for(i=0;i<n;i++)		//利用字符串输入,省时 
			scanf("%s",&str[i]);
		for(i=0;i<n;i++)		//找出有石块的田地 
			for(j=0;j<m;j++)
				if(str[i][j]=='S')
					sum++;
		dfs(0,0);
		if(flag)
			puts("YES");
		else
			puts("NO");
	}
	return 0;
}


例题三:

题目来源:POJ-1342:Lotto

题目大意:从 k数组中选择 6 个元素的组合,写出所有的可能情况。

题目分析:其实这个题目有个不好处理的就是最后一个案例不能有换行。把案例看成以文件读入读出,第一个输出不换行,第二个输入再换行。递归实现从 n 个元素中选择 m  个元素,常规法.从头到尾一个一个的找(深度优先搜寻),并递归替换。

AC代码:

#include <stdio.h>
#include <string.h>
int a[50],b[7];
int n;
void dfs(int top,int sum)		//深度优先搜索 
{
	if(sum>=6)		//满足条件输出 
	{
		for(int i=0;i<6;i++)
		{
			if(i)
				printf(" ");
			printf("%d",b[i]);
		}
		puts("");
		return ;
	}
	for(int i=top;i<n;i++)		//不满足条件继续搜索 
	{
		b[sum]=a[i];
		dfs(i+1,sum+1);		
	}
	return ;
}

int main()
{
	int j;
	while(scanf("%d",&n),n)
	{
		if(j++)		//输出空行 
			puts("");
		for(int i=0;i<n;i++)
			scanf("%d",&a[i]);
		dfs(0,0);
	}
	return 0;
}

例题四:

题目来源:POJ-1181:变形课

题目大意:变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形咒语的一个统一规律:如果咒语是以a开头b结尾的一个单词,那么它的作用就恰好是使A物体变成B物体。现在将他所会的所有咒语都列成了一个表,他想让你帮忙计算一下他是否能完成老师的作业,将一个B(ball)变成一个M(Mouse)。

题目分析:首先搜索首字母为“B”的单词,然后标记已搜索过,再搜索首字母为上一个单词的尾字母并标记,直到找到尾字母为“M”的单词,输出“Yes.”,如果搜索不到此单词输出“No.”。

AC代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

int vis[1000];
int flag,k;

struct node		//构建结构体,分别记录单词的首字母和尾字母 
{
	int start;
	int end;
}word[1000];

void dfs(char c)		//深度优先搜索 
{
	char temp;
	if(c=='m')		//判断是否找到字母“M” 
	{
		flag=1;
		return ;
	}
	for(int i=1;i<k;i++)
		if(vis[i]==0&&word[i].start==c)		//单词没有被搜索过,并且首字母为上一个字母的尾字母 
		{
			temp=c;
			c=word[i].end;
			vis[i]=1;		//对于搜索过的单词进行标记 
			dfs(c);
			c=temp;
		}
}

int main()
{
	int i,len;
	char a[100];
	k=1;		//初始化 
	while(gets(a)!=NULL)
	{
		if(strcmp(a,"0")==0)		//判断是否输入结束 
		{
			flag=0;
			dfs('b');		//搜索首字母为“b” 的单词 
			if(flag)
				puts("Yes.");
			else
				puts("No.");
			k=1;		//初始化 
		}
		else
		{
			len=strlen(a);
			word[k].start=a[0];
			word[k].end=a[len-1];
			vis[k]=0;
			k++;
		}
	}
	return 0;
}

例题五:

题目来源:POJ-1045:Fire Net

题目大意:在有若干个城墙的n*n的城市里建立大炮,大炮威力很大,除了城墙都能打透,所以两门大炮不能在同一行,或同一列,除非中间有城墙隔着,问最多能建立多少个大炮。

题目分析:从左上角开始搜索,判断是否能安排大炮(此位置的上方和左方不能有大炮,除非有城墙隔着),能安排大炮就标记并统计大炮数目,以此类推,直到所有地方不能安排大炮,输出最多安排大炮的数量。

AC代码:

 

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
char str[5][5];
int t,sum;
bool vis(int x,int y)		//判断此位置的上方,左方是否有大炮或者城墙 
{
    int i;
    for(i=x-1;i>=0;i--)
    {
        if(str[i][y]=='0')
            return false;
        if(str[i][y]=='X')
            break;
    }
    for(i=y-1;i>=0;i--)
    {
        if(str[x][i]=='0')
            return false;
        if(str[x][i]=='X')
            break;
    }
    return true;
}
void dfs(int x,int y)
{
    int a,b;
    if(x==t*t)		//是否已经全部搜索完毕 
    {
        if(y>sum)		//sum为最多大炮数量 
        {
            sum=y;
            return ;
        }
    }
    else
    {
        a=x/t;		//a为行数 
        b=x%t;		//b为列数 
        if(str[a][b]=='.'&&vis(a,b))		//判断此位置是否为空地 
        {
            str[a][b]='0';		//标记已安排大炮 
            dfs(x+1,y+1);		//搜索数目和安排的大炮数目分别+1 
            str[a][b]='.';
        }
        dfs(x+1,y);		//搜索数目+1 
    }
}
int main()
{
    int i;
    while(scanf("%d",&t)&&t)
    {
        sum=0;
        for(i=0;i<t;i++)		//输入地图 
            scanf("%s",str[i]);
        dfs(0,0);		//从左上角开始搜索 
        printf("%d\n",sum);
    }
    return 0;
}

例题六:

题目来源:ZOJ-2734:Exchange Cards

题目大意:用自己已有的卡片等价交换自己想要的卡片,一共有多少种交换方法。

题目分析:首先将自己所拥有的卡片的价值和数量输入并保存在结构体中,然后进行卡片交换,记录一共有多少种符合等价交换的交换方式,(考查深度优先搜索)。

AC代码:

 

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int sum,m;
struct note		//建立结构体 
{
	int value;
	int num;
}a[11];
void dfs(int x,int y,int z)		//深度优先搜索 
{
	if(y==z)		//符合条件 
	{
		sum++;
		return ;
	}
	if(y>z||x==m)		//价值超出,不符合条件 
		return ;
	for(int j=0;j<=a[x].num;j++)
		dfs(x+1,y+j*a[x].value,z);		//递归 
}
int main()
{
	int n,i,b=-1;
	while(~scanf("%d%d",&n,&m))
	{
		for(i=0;i<m;i++)
			scanf("%d%d",&a[i].value,&a[i].num);
		b++;
		if(b)
			puts("");
		sum=0;
		dfs(0,0,n);
		printf("%d\n",sum);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值