深搜刷题记录

一:挖地雷

首先观察数据范围 N <= 20 考虑暴搜

暴搜的几个必要组成

1.dfs函数的参数选择

2.搜索到结果时的判定

3.回溯

本题中,我们搜索记录的是可以挖到的地雷的数量,所以肯定有一个参数是记录地雷总数,然后需要知道我们当前是挖的哪一个地雷(因为我们可以从任意一个地雷开始挖)。由于最后需要输出最优答案的路径,所以这个需要一个临时数组来存放路径,那么就需要一个参数来记录这个临时数组的长度,也可以说是当前已经挖了多少个地雷

代码:

/* */
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAX = 1e5+7,N = 25;
int g[N][N];//存连接图 
int a[N]; 
int vis[N];
int n,num,ans;
int c[N];//需要输出路径时 额外定义的临时数组
int res[N];//答案数组 满足条件时将c重新复制一遍
void dfs(int x,int idx,int sum)
{
	//当前访问的地窖编号 已经访问了几个地窖(c数组的长度) 地雷数 
	if(sum > ans)
	{
		//出现了更优解
		ans = sum;
		num = idx;//几个地窖
		for(int i=0;i<idx;i++)
		res[i] = c[i]; 
	}
	for(int i=1;i<=n;i++)
	{
		if(g[x][i] && !vis[i])
		{
			vis[i] = 1;
			c[idx] = i;
			dfs(i,idx+1,sum+a[i]);
			vis[i] = 0;
		}
	}
	return;
	
} 
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			int x;
			cin>>x;
			g[i][j] = x;
		}
	}
	// 可以从任何一个地雷开始挖 每一个点都搜索一下 
	for(int i=1;i<=n;i++)
	{
		vis[i] = 1;
		c[0] = i;
		dfs(i,1,a[i]);
		vis[i] = 0;
	}
	for(int i=0;i<num;i++)cout<<res[i]<<" ";
	cout<<endl<<ans;
}
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);
    cout.tie(0);
    //cout<<fixed<<setprecision(2);
    int t=1;
    //cin>>t;
    while(t--)
      solve();
    return 0;
} 
二:P1434 滑雪
 

首先观察数据范围:在100以内 考虑剪枝和记忆化搜索

本题与上面题目类似 我们都可以从任何一个地方开始往下滑 所以我们从每一个点开始深搜记录最大值

记忆化搜索:既然我们从某一个点滑着滑着到了我之间已经(记录过的)从这个点开始往下滑的最大值了,就不需要再从他开始往下搜索了 记录值返回即可 

搜索到没有满足条件的点时 说明他的周围已经没有比他还大的点了 那么只需要取他的周围点的最大值加1就是他的最大值 (回溯的时候更新值)

/* */
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAX = 1e5+7,N = 105;
int res[N][N];
int g[N][N];
int n,m,ans;
int dx[4] = {0,1,-1,0};
int dy[4] = {1,0,0,-1};
int dfs(int x,int y)
{
	if(res[x][y])return res[x][y];//记忆化搜索
	res[x][y] = 1;//默认初始 值为1
	for(int i=0;i<4;i++)
	{
		int xx = x+dx[i];
		int yy = y+dy[i];
		if(xx>=1&&yy>=1&&xx<=n&&yy<=m&&g[xx][yy]>g[x][y])
		{
			dfs(xx,yy);
			res[x][y] = max(res[x][y],res[xx][yy]+1);//回溯更新
		}
	}
	return res[x][y]; 
}
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>g[i][j];
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			ans = max(ans,dfs(i,j));
		}
	}
	cout<<ans;
}
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);
    cout.tie(0);
    //cout<<fixed<<setprecision(2);
    int t=1;
    //cin>>t;
    while(t--)
      solve();
    return 0;
} 
三:P4017 最大食物链计数
 

 

有关食物链问题基本和拓扑排序有关 因为食物链中一般没有自环

观看此题:要找的是最左端是不会捕捉其他生物的生产者,最右端是不会被其他生物捕捉的最厉害的消费者,所以跟一个点的入度和出度有关 考虑拓扑排序 需要借助队列来实现

那么我们首先需要找到入度为0的点,让他入队 通过他去增加与他连接着的消费者的sum值,然后将那些与他连接着的点的入度-1,如果为0的话 让他也入队 让他当作新的起始点去更新他的消费者的sum值

/* */
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAX = 1e5+7,mod = 80112002,N = 5005;
vector<int>g[N];
queue<int>q;
int sum[N];
int in[N],out[N];
void topoSort()
{
	while(!q.empty())
	{
		int t = q.front();
		q.pop();
		for(auto i : g[t])
		{
			in[i]--;
			if(in[i] == 0)
			q.push(i);
			sum[i]=(sum[i]+sum[t])%mod;
		}
	}
}
void solve()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		cin>>x>>y;
		in[y]++,out[x]++;
		g[x].push_back(y);
	}
	for(int i=1;i<=n;i++)
	{
		if(in[i] == 0)
		{
			sum[i] = 1;
			q.push(i);
		}
	}
	topoSort();
	int ans = 0;
	for(int i=1;i<=n;i++)
	{
		if(out[i] == 0)
		{
			ans=(ans+sum[i])%mod;
		}
	}
	cout<<ans%mod;
}
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);
    cout.tie(0);
    //cout<<fixed<<setprecision(2);
    int t=1;
    //cin>>t;
    while(t--)
      solve();
    return 0;
} 

本人是个小白,希望佬们看了代码给些宝贵的建议~写的详细只是为了以后自己能看懂(●'◡'●)

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值