0
点赞
收藏
分享

微信扫一扫

[Acwing提高]DFS连通性模型与搜索顺序

JamFF 2022-11-25 阅读 28


[Acwing提高]DFS连通性模型与搜索顺序

知识点

题目

扩展方式

类型

迷宫

看是否连通

DFS连通性

红与黑

Flood-Fill

DFS连通性

马走日

统计路径数

DFS搜索顺序

单词接龙

字符串公共

dfs搜索顺序

分成互质组

组合搜索

dfs

题目

迷宫

思路
起点不一定能走啊
代码

#include<bits/stdc++.h>
using namespace std;

const int N=110;
char g[N][N];
bool st[N][N];
int n,k;
int xa,ya,xb,yb;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
bool dfs(int x,int y)
{
if(g[x][y]=='#')return 0;
if(x==xb&&y==yb)return 1;
st[x][y]=1;
for(int i=0;i<4;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<0||b<0||a>=n||b>=n)continue;
if(st[a][b])continue;
if(g[a][b]=='#')continue;

if(dfs(a,b))return 1;
}
return 0;
}
int main()
{
scanf("%d",&k);
while(k--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%s",&g[i]);
memset(st,0,sizeof st);

scanf("%d%d%d%d",&xa,&ya,&xb,&yb);

if(dfs(xa,ya))puts("YES");
else puts("NO");
}
return 0;
}

红与黑

思路
DFS实现Flood-Fill

代码

#include<bits/stdc++.h>
using namespace std;
const int N=25;
char g[N][N];
bool st[N][N];
int n,m;
int sx,sy;
int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
int dfs(int x,int y)
{
int cnt=1;
st[x][y]=1;
for(int i=0;i<4;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<0||b<0||a>=n||b>=m)continue;
if(st[a][b])continue;
if(g[a][b]=='#')continue;
cnt+=dfs(a,b);
}
return cnt;
}
int main()
{
while(cin>>m>>n&&n||m)
{
memset(st,0,sizeof st);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>g[i][j];
if(g[i][j]=='@')sx=i,sy=j;
}
cout<<dfs(sx,sy)<<endl;
}
return 0;
}

马走日

思路

统计路径数,要把整个图作为一个节点来考虑,描述状态为马的位置(x,y)以及当前是第几步了

[Acwing提高]DFS连通性模型与搜索顺序_#include

代码

#include<bits/stdc++.h>
using namespace std;

const int N=10;
int n,m;
bool st[N][N];
int ans;
int dx[]={1,1,-1,-1,2,2,-2,-2};
int dy[]={2,-2,2,-2,1,-1,1,-1};

void dfs(int x,int y,int cnt)
{
if(cnt==n*m)
{
ans++;
return;
}
for(int i=0;i<8;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<0||b<0||a>=n||b>=m)continue;
if(st[a][b])continue;
st[a][b]=1;
dfs(a,b,cnt+1);
st[a][b]=0;//回溯恢复
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
int x,y;
cin>>n>>m>>x>>y;
memset(st,0,sizeof st);
ans=0;
st[x][y]=1;//标记起点
dfs(x,y,1);
printf("%d\n",ans);
}

return 0;
}

yxc的

#include<bits/stdc++.h>
using namespace std;

const int N=10;
int n,m;
bool st[N][N];
int ans;
int dx[]={1,1,-1,-1,2,2,-2,-2};
int dy[]={2,-2,2,-2,1,-1,1,-1};

void dfs(int x,int y,int cnt)
{
if(cnt==n*m)
{
ans++;
return;
}
st[x][y]=1;

for(int i=0;i<8;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<0||b<0||a>=n||b>=m)continue;
if(st[a][b])continue;

dfs(a,b,cnt+1);
}
st[x][y]=0;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int x,y;
cin>>n>>m>>x>>y;

ans=0;
dfs(x,y,1);
printf("%d\n",ans);
}

return 0;
}

单词接龙

思路
先枚举符合首字母的,然后dfs搜,状态为拼接出来的字符串和最后用了哪个字符串
比较恶心的是处理公共部分长度
贪心一波肯定公共部分长度越短越好
我们可以直接预处理出公共长度存到二维数组里面(因为两个字符串拼接先后不同的话公共部分长度不一样的)

当我们要判断前串后缀与后串前缀是否相同的时候可以借助substr完成

对于答案更新:不用像其他dfs一样写边界直接更新即可

代码

#include<bits/stdc++.h>
using namespace std;

const int N=21;

int n;
string word[N];
int g[N][N];
int used[N];
int ans;

void dfs (string dragon,int last)//当前拼出来的以及上个用了哪个
{
ans=max((int)dragon.size(),ans);
used[last]++;

for(int i=0;i<n;i++)
if(g[last][i]&&used[i]<2)
dfs(dragon+word[i].substr(g[last][i]),i);

used[last]--;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)cin>>word[i];
char start;
cin>>start;

//预处理公共部分
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
string a=word[i],b=word[j];
for(int k=1;k<min(a.size(),b.size());k++)
if(a.substr(a.size()-k,k)==b.substr(0,k))
{
g[i][j]=k;
break;
}
}
for(int i=0;i<n;i++)
if(word[i][0]==start)
dfs(word[i],i);
cout<<ans<<endl;
}

分成互质组

思路
先枚举组数
如果分完了,那么更新最小值

决策:
1把某个数加到最后一组
2开个新组

如果可以选1那么就不选2
证:如果一个数放到下一组可以得到最优解,那么把这个数抠出来放原来组也可以得到最优解。因为抠出来以后新一组(后续搜索完整的时候)数之间还是互质的。

对于组内的数,我们要采用组合搜索的方式

[Acwing提高]DFS连通性模型与搜索顺序_#include_02

代码

#include<bits/stdc++.h>
using namespace std;

const int N=15;
int n;
int p[N];
int group[N][N];
bool st[N];
int ans=N;

int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}

bool check(int group[],int gc,int i)//判组内互质
{
for(int j=0;j<gc;j++)
if(gcd(p[group[j]],p[i])>1)
return 0;
return 1;
}
//g当前做到哪一组,gc表示当前枚举到第几个数,tc表示已经处理多少数,st表示组内从哪个数开始枚举
void dfs(int g,int gc,int tc,int start)
{
if(g>=ans)return;
if(tc==n)ans=g;

bool flag=1;
for(int i=start;i<n;i++)//组合枚举
if(!st[i]&&check(group[g],gc,i))
{
st[i]=1;
group[g][gc]=i;
dfs(g,gc+1,tc+1,i+1);
st[i]=0;

flag=0;
}
if(flag)dfs(g+1,0,tc,0);
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)cin>>p[i];

dfs(1,0,0,0);

cout<<ans<<endl;
return 0;
}

总结

dfs比想象难很多,代码实现裂开了啊啊

dfs参数(状态的描述,当前操作描述)

可以开个二维数组预处理关系

明确答案边界,如果找不到可能就是搜不下去的时候直接更新答案


举报

相关推荐

0 条评论