备战蓝桥杯---DFS基础刷题

话不多说,直接看题:

1.注意搜索顺序+枚举方式

首先,看到数据范围,我们就不可以直接每一轮3次的暴力。

我们可以发现a^2的大部分情况>2a以及a+1,并且,我们发现其实1的操作是没有必要的(因为2a以经包括了),因此,我们可以把枚举过程想象成只进行2/3操作,只有实在不行时才选1,注意,如果直接正着做会比较麻烦,如这组数据:

正着做的话存在一个问题那就是我们不知道何时+1,因为+1后可能使后面更优,于是我们考虑反着看就可以发现反着符合刚才说的:

我们考虑最后变成b的前一步,我们发现有只有两种情况,就是*2加上剩下的用加1的操作以及平方加上剩下的用加1的操作(或者就是b-a(当两种都会超b))。

同时加上记忆化搜索即可。

下面是AC代码:

#include<bits/stdc++.h>
using namespace std;
int t;
long long a,b;
map<long long,long long> mp;
long long dfs(long long b){
    if(b==a) return 0;
    if(mp.count(b)!=0) return mp[b];
    mp[b]=abs(b-a);
    long long cc=sqrt(b);
    if(cc>=a) mp[b]=min(dfs(cc)+1+b-cc*cc,mp[b]);
    if(b/2>=a) mp[b]=min(dfs(b/2)+1+b%2,mp[b]);
    return mp[b];
    
}
int main(){
    cin>>t;
    while(t--){
        mp.clear();
        scanf("%lld%lld",&a,&b);
        cout<<dfs(b)<<endl;
    }
}

2.树的遍历:

首先我们可以给每一个节点赋值(即第一行1,第二行2,3.。。。)

同时因为数字是从右往左输出,我们可以调整一下中序以及前序的左右遍历顺序,然后我们按照节点值从小到大输出即可。

下面是AC代码:

#include<bits/stdc++.h>
using namespace std;
int n,mid[40],pre[40],cnt;
struct node{
    int id,zhi;
}v[1000];
void dfs(int root,int l,int r,int ii){
    if(l>r) return;
    int m=l;
    while(pre[root]!=mid[m]&&m<r) m++;
    v[++cnt]={ii,mid[m]};
    dfs(root+1+m-l,m+1,r,2*ii);
    dfs(root+1,l,m-1,2*ii+1);
}
bool cmp(node a,node b){
    return a.id<b.id;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>mid[i];
    for(int i=1;i<=n;i++) cin>>pre[i];
    dfs(1,1,n,1);
    sort(v+1,v+cnt+1,cmp);
    for(int i=1;i<=cnt;i++){
        cout<<v[i].zhi<<" ";
    }
    cout<<endl;
}

3.图的DFS:

我们可以把问题抽象成求最小的环,首先我们把不是环的枝叶去掉,然后因为一个点只有一条出边,我们没有必要用存图的方式来记录,我们开个nxt数组即可,最后进行DFS即可。

下面是AC代码:

#include<bits/stdc++.h>
using namespace std;
int n,nxt[200010],inc[200010],vis[200010];
void del(int hh){
	vis[hh]=1;
	inc[nxt[hh]]--;
	if(inc[nxt[hh]]==0) del(nxt[hh]);
}
int deal(int hh){
	if(vis[hh]!=0) return 0;
	vis[hh]=1;
	return deal(nxt[hh])+1;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d",&nxt[i]);
		inc[nxt[i]]++;
	}
	for(int i=1;i<=n;i++){
		if(vis[i]==1) continue;
		if(inc[i]==0) del(i);
	}
	int ans=100000000;
	for(int i=1;i<=n;i++){
		if(vis[i]==1) continue;
		ans=min(ans,deal(i));
	}
	cout<<ans;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值