dfs用于解决连通性,路径查找,求解的个数
B3625 迷宫寻路
1.思路:用dfs寻找到一条路,不用回溯,因为我们只需要找到一条路就可以
2.代码:
#include <bits/stdc++.h>
using namespace std;
char a[105][105];
int vis[105][105];
int sx[4]={-1,0,1,0};
int sy[4]={0,1,0,-1};
int f=0;
int n,m;
void dfs(int x,int y)
{
if(x==n&&y==m)
{
f=1;
return;
}
else
{
for(int i=0;i<4;i=i+1)
{
int nx=x+sx[i];
int ny=y+sy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&a[nx][ny]=='.'&&vis[nx][ny]==0)
{
vis[nx][ny]=1;
dfs(nx,ny);
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i=i+1)
{
for(int j=1;j<=m;j=j+1)
{
cin>>a[i][j];
}
}
vis[1][1]=1;
dfs(1,1);
if(f==0)
{
cout<<"No";
}
else
{
cout<<"Yes";
}
}
P1706 全排列问题
1.思路:用dfs寻找到所有路径,即枚举出所有情况
2.代码:
#include <bits/stdc++.h>
using namespace std;
int a[1005];
int vis[1005];
void dfs(int n,int len,int num)
{
if(num==n)
{
for(int i=1;i<=n;i=i+1)
{
cout<<" "<<a[i];
}
cout<<endl;
}
else
{
for(int i=1;i<=n;i=i+1)
{
if(vis[i]==0)
{
vis[i]=1;
num=num+1;
a[num]=i;
dfs(n,n,num);
num=num-1;
vis[i]=0;
}
}
}
}
int main()
{
int n;
memset(vis,0,sizeof(vis));
cin>>n;
dfs(n,n,0);
}
P1451 求细胞数量
1.思路:求连通块的变形问题,所以我们可以用dfs求连通块,
2.代码:
#include <bits/stdc++.h>
using namespace std;
int n,m;
char a[105][105];
int sx[4]={-1,0,1,0};
int sy[4]={0,1,0,-1};
int vis[105][105];
void dfs(int x,int y)
{
for(int i=0;i<4;i=i+1)
{
int nx=x+sx[i];
int ny=y+sy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&vis[nx][ny]==0&&a[nx][ny]!='0')
{
vis[nx][ny]=1;
dfs(nx,ny);
}
}
}
int ans=0;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i=i+1)
{
for(int j=1;j<=m;j=j+1)
{
cin>>a[i][j];
}
}
for(int i=1;i<=n;i=i+1)
{
for(int j=1;j<=m;j=j+1)
{
if(vis[i][j]==0&&a[i][j]!='0')
{
vis[i][j]==1;
ans++;
dfs(i,j);
}
}
}
cout<<ans;
}
P1219 [USACO1.5] 八皇后 Checker Challenge
1.思路:分析这道题的条件:1.每行每列都只能有一个棋子 2.每个对角线都只能有一个棋子。所以我们要在每次dfs之前都要判断是否满足条件
2.代码:
#include <bits/stdc++.h>
using namespace std;
int visy[15];
int visc[30];
int visd[30];
int a[15][15];
int h[15];
int n;
int z;
int ans;
void dfs(int x)
{
if(x==n+1)
{
if(z<3)
{
for(int i=1;i<=n;i=i+1)
{
if(i==n)
{
cout<<h[i];
}
else
{
cout<<h[i]<<" ";
}
}
cout<<endl;
z++;
}
ans++;
}
else
{
for(int i=1;i<=n;i=i+1)
{
if(visy[i]==0&&visc[x+i]==0&&visd[x-i+n]==0)
{
visy[i]=1;
visc[x+i]=1;
visd[x-i+n]=1;
h[x]=i;
dfs(x+1);
h[x]=0;
visy[i]=0;
visc[x+i]=0;
visd[x-i+n]=0;
}
}
}
}
int main()
{
cin>>n;
dfs(1);
cout<<ans;
}
P1019 [NOIP2000 提高组] 单词接龙
1.思路:分析题目条件:1.首尾有共同的部分可以连接 2.特殊情况:如果两个单词存在包含关系,那么不能连接。所以我们在进行dfs之前开一个二维数组,记录第i个单词是否能接第j个单词
2.代码:
P5194 [USACO05DEC] Scales S
1.思路:这是比较特殊的一类dfs,我称之为选择式dfs,我们在定义下一步的方向是选与不选,放左脑或右脑,另外,我们还可以加一个剪枝,即如果前面所有砝码都加起来都达不到当前的最大值,那么就可以停止搜索了,我们可以用前缀和来实现。
2.代码:
P1378 油滴扩展
1.思路:分析题目条件:1.扩展到接触其他油滴或者是边界即停止 2.油滴放置有先后顺序,且这个顺序由我们进行枚举 那么我们可以创建一个二维数组来存储每两个油滴之间的距离,在dfs中,来变化油滴之间的距离
2.代码:
#include <bits/stdc++.h>
using namespace std;
int n;
double cx1,cy1,cx2,cy2;
double x[7];
double y[7];
double d[7];
int vis[7];
int r[7];
int num1;
double h[7][7];
double max1;
void dfs(int s,double mian)
{
if(s==n)
{
max1=max(max1,mian);
}
else
{
for(int i=1;i<=n;i=i+1)
{
if(vis[i]==0)
{
double min1=9999;
int minx;
for(int j=1;j<=num1;j=j+1)
{
if(h[i][r[j]]<min1)
{
min1=h[i][r[j]];
minx=j;
}
}
double min2=min(min1,d[i]);
if(min2<0)
{
vis[i]=1;
num1++;
r[num1]=i;
dfs(s+1,mian);
r[num1]=0;
num1--;
vis[i]=0;
}
else
{
for(int j=1;j<=n;j=j+1)
{
if(i!=j)
{
h[j][i]=h[j][i]-min2;
}
}
vis[i]=1;
num1++;
r[num1]=i;
dfs(s+1,mian+3.1415926535*min2*min2);
for(int j=1;j<=n;j=j+1)
{
if(i!=j)
{
h[j][i]=h[j][i]+min2;
}
}
r[num1]=0;
num1--;
vis[i]=0;
}
}
}
}
}
double juli(int x1,int y1,int x2,int y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
cin>>n;
cin>>cx1>>cy1>>cx2>>cy2;
if(cx1>cx2)
{
int t=cx1;
cx1=cx2;
cx2=t;
}
if(cy1>cy2)
{
int t=cy1;
cy1=cy2;
cy2=t;
}
for(int i=1;i<=n;i=i+1)
{
cin>>x[i]>>y[i];
d[i]=min(min(abs(x[i]-cx1),abs(x[i]-cx2)),min(abs(y[i]-cy1),abs(y[i]-cy2)));
}
for(int i=1;i<=n;i=i+1)
{
for(int j=i+1;j<=n;j=j+1)
{
h[i][j]=juli(x[i],y[i],x[j],y[j]);
h[j][i]=h[i][j];
}
}
dfs(0,0);
cout<<fixed<<setprecision(0)<<(cx2-cx1)*(cy2-cy1)-max1;
}