深度优先遍历题目题解
1.滑雪比赛
题目:
狗狗们的全国冬季滑雪运动会的场地是一个M*N的矩阵。矩阵中的每个小方格上的数代表的是每块地方的高度,范围是0到1000000000之间的整数。
矩阵中某些小方格被认为是中转点,主办方希望能够设置一个最小的D值,使得每只狗狗从任意一个中转点出发都可以到达其他任意的中转点。每次行走都是向相邻的小方格移动的,相邻的小方格指得是上下左右直接相接的小方格。如果相邻的小方格之间的高度差的绝对值小于等于D,则狗狗可以在两个相邻的小方格之间移动。
请计算这个最小的D值,使得狗狗能够从任意一个中转点出发通过移动到达其他任意中转点。
题目条件:
1.第一行是两个正整数M和N。
2.第二行到到M+1行,每行N个整数,表示每个小方格的高度。
3.第M+2行到第2M+1行,每行N个整数,要么是0,要么是1,1表示该位置所对应的小方格是中转点,0表示该位置所对应的小方格不是中转点。
分析:
首先最普通的方法就是枚举D值并判断可不可以做到,很明显这样做时间会超限很多,而每次灌水最多需要M*N的时间复杂度,每次二分之后检查标记数组,从随意指定的中转点出发,只要检查数组是别的中转点被标记了就可以。进一步,如果D值越小,那么越难完成,这里就有单调性,我们可以二分枚举答案,枚举是判断即可。
程序:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[501][501],b[501][501],c[501][501],p,q;
bool f(int x,int y,int z)
{
if(abs(x-y)<=z)
return 1;
return 0;
}
void zs(int x,int y,int z)
{
if(x<1||y<1||x>n||y>m||c[x][y])
return;
c[x][y]=1;
if(f(a[x][y],a[x+1][y],z))
zs(x+1,y,z);
if(f(a[x][y],a[x-1][y],z))
zs(x-1,y,z);
if(f(a[x][y],a[x][y+1],z))
zs(x,y+1,z);
if(f(a[x][y],a[x][y-1],z))
zs(x,y-1,z);
}
int check(int x)
{
zs(p,q,x);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(b[i][j]&&!c[i][j])
{
memset(c,0,sizeof(c));
return 0;
}
memset(c,0,sizeof(c));
return 1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>b[i][j];
if(b[i][j])
{
p=i;
q=j;
}
}
int l=1,r=1e9;
while(l<r)
{
int mid=(l+r)/2;
if(!check(mid))
l=mid+1;
else
r=mid;
}
cout<<l<<'\n';
return 0;
}
2.珍珠
题目:
有n颗形状和大小都一致的珍珠,它们的重量都不相同。n为整数,所有的珍珠从1到n编号。你的任务是发现哪颗珍珠的重量刚好处于正中间,即在所有珍珠的重量中,该珍珠的重量列(n+1)/2位。下面给出将一对珍珠进行比较的办法:
给你一架天平用来比较珍珠的重量,我们可以比出两个珍珠哪个更重一些,在作出一系列的比较后,我们可以将某些肯定不具备中间重量的珍珠拿走。
例如,下列给出对5颗珍珠进行四次比较的情况:
1、珍珠2比珍珠1重
2、珍珠4比珍珠3重
3、珍珠5比珍珠1重
4、珍珠4比珍珠2重
根据以上结果,虽然我们不能精确地找出哪个珍珠具有中间重量,但我们可以肯定珍珠1和珍珠4不可能具有中间重量,因为珍珠2、4、5比珍珠1重,而珍珠1、2、3比珍珠4轻,所以我们可以移走这两颗珍珠。
写一个程序统计出共有多少颗珍珠肯定不会是中间重量。
题目条件:
1.输入文件第一行包含两个用空格隔开的整数N和M,其中1<=N<=99,且N为奇数,M表示对珍珠进行的比较次数,接下来的M行每行包含两个用空格隔开的整数x和y,表示珍珠x比珍珠y重。
分析:
这里需要查找不可能是中间重量的珍珠数量,每次我们可以灌水来计算一定比考虑的珍珠重的和一定比考虑珍珠轻的,只要有一个比n/2要大,那么答案就加一,可以用两个函数来计算,比较方便。
程序:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[101][101],b[101],c[101],s,l,ans;
void za(int x)
{
for(int i=1;i<=n;i++)
if(a[x][i]&&!b[i])
{
b[i]=1;
l++;
za(i);
}
}
void zb(int x)
{
for(int i=1;i<=n;i++)
if(a[i][x]&&!c[i])
{
c[i]=1;
s++;
zb(i);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
a[x][y]=1;
}
for(int i=1;i<=n;i++)
{
za(i);
zb(i);
if(l>n/2||s>n/2)
ans++;
s=0;
l=0;
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
}
cout<<ans<<endl;
return 0;
}
3.坏草岛屿
题目:
贝茜和其他牛一样正在用力咀嚼嫩草,没有考虑到生态环境问题。她注意到她最喜欢宽阔牧场上那种矮矮的草。野草长到1米高的时候很难拒绝而且口味也老。这些坏草随着高度增加将越来越坏。继续嚼,她意识到这令人倒胃口的食物长得像山一样,好像是美味、丰富的野草海洋中矗立着的一个个岛屿。贝茜穿上工作服,她决定勘测一下她田块中一共有多少块坏草小山。她把要勘测田块绘制成一个地图,地图上包含R(1<R<=1000)行和C(1<C<=1000)列个1米*1米的正方形。她测量其中的每一块,并记录下其中草的高度。她把所有新鲜美味的草都标记为0。她开始统计这些岛屿的个数。沿着任意方向相邻(8个方向)的两个区域将被认为是同一个岛屿的不同部分。请计算提供的每个地图上有多少个坏草岛屿。
题目条件:
1.第1行:两个用空格隔开的整数R,C。
2.第2..R+1行:田块信息。
3.输出坏草岛屿的数量。
分析:
这道题目是一道简单的求连通块数量的问题,一个遍历函数把每一个长了坏草的地方走一遍,然后他这个草的高度并不重要,只需要看他是否超过0,然后每次看这个点有没有走过,输出答案即可。
程序:
#include<bits/stdc++.h>
using namespace std;
int r,c,a[1001][1001],b[1001][1001],ans;
void zs(int x,int y)
{
if(x<1||y<1||x>r||y>c||b[x][y]||!a[x][y])
return;
b[x][y]=1;
zs(x-1,y);
zs(x+1,y);
zs(x,y-1);
zs(x,y+1);
zs(x+1,y+1);
zs(x+1,y-1);
zs(x-1,y+1);
zs(x-1,y-1);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>r>>c;
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
cin>>a[i][j];
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
if(!b[i][j]&&a[i][j])
{
ans++;
zs(i,j);
}
cout<<ans<<'\n';
return 0;
}
浙公网安备 33010602011771号