比题解1更简单易懂的DFS
- 前言:一开始我不明白什么时候输出
infinity
,然后去看了题解1的代码,发现使用了dfs+回溯,其中的逻辑并不是特别容易理解。但是通过阅读那个题解我明白了什么时候需要输出infinity
,下面讲解思路
- 输出
infinity
的条件:相信很多卡在这道题的选手都是对这一点有困扰,这里我举一个浅显的例子。假设,通过abbbb
这样的选择我们可以从0到达终点,但如果同时存在aa
这样的选择可以使我们从0到达0,那么最终符合要求的字符串可以有无限多个,其正则式为(aa)*abbbb
,且每多一个aa
其字典序都严格变小,所以这时候需要输出infinity
- 知道了
infinity
的判断思路后,我们具体要怎么实现呢?很简单,因为DFS时我们先找走a[i]
步的情况来使得结果的字典序尽可能小,所以如果存在这样的环路,那么最终的访问序列中一定有某个结点的访问次数大于1,我们设置一个vis[N]
数组记录DFS过程中结点的访问次数即可。注意在最终的判断时只需要判断存在于答案访问序列中的点,而不是DFS过程中所有的点
- ac代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,a[N],b[N];
int flag,flag2,vis[N];
char ans[N];
char ans2[N];
void dfs(int x,int dep){
if(flag) return ;
if(vis[x]>0) {vis[x]++;return;}
else vis[x]++;
if(x==n-1) {
for(int i=0;i<dep;i++)
ans2[i]=ans[i];
flag=1;
return ;
}
if(x+a[x]>0&&x+a[x]<n){
ans[dep]='a';
dfs(x+a[x],dep+1);
}
if(x+b[x]>0&&x+b[x]<n){
ans[dep]='b';
dfs(x+b[x],dep+1);
}
}
void solve(){
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++) cin>>b[i];
dfs(0,0);
if(flag) {
int tmp=0;
for(int i=0;i<strlen(ans2);i++){
if(vis[tmp]>1) flag2=1;
if(ans2[i]=='a') tmp+=a[tmp];
else tmp+=b[tmp];
}
if(flag2) cout<<"Infinity!"<<endl;
else cout<<ans2<<endl;
}
else cout<<"No solution!"<<endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
//cin>>T;
while(T--) solve();
}