例题一:
题目大意:约翰的农场被暴风雨给淹没了,损失很大,他的保险公司将支付给他,但是支付金额取决于被淹没的最大面积。这个农场是一个边长分别为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;
}
例题六:
题目大意:用自己已有的卡片等价交换自己想要的卡片,一共有多少种交换方法。
题目分析:首先将自己所拥有的卡片的价值和数量输入并保存在结构体中,然后进行卡片交换,记录一共有多少种符合等价交换的交换方式,(考查深度优先搜索)。
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;
}