暑假训练第14天学习

文章展示了两道编程题目,分别涉及滑雪路径的最大距离计算和食物链计数,利用记忆化搜索优化算法提高效率。第一题中,从高处滑向低处,计算最大滑雪距离;第二题中,通过图的深度优先搜索计算最长食物链。第三题是猫粮规划问题,使用动态规划找到满足条件的组合数量。
摘要由CSDN通过智能技术生成

洛谷:滑雪

知识点:记忆化搜索

记忆化搜索其实就是在你暴搜的时候,某些点可以由其他点转移的过程中已经确定答案了,这些点往往可以不用去搜索这样可以减少时间的复杂度

5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[1001][1001];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
ll s[1001][1001];
//从i,j为起点的最大距离 
ll ok[1001][1001];
ll n,m;
int dfs(int x,int y)
{
	if(ok[x][y])return s[x][y];
	//记忆化搜索
	ok[x][y]=1;
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i];
		int ny=y+dy[i];
		if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&(a[nx][ny]<a[x][y]))
		{
			dfs(nx,ny);
			//因为是从高处向低处走所以nx,ny的坐标要小于x和y的坐标 
			s[x][y]=max(s[x][y],s[nx][ny]+1);
		}
	}
	return s[x][y];
	
 } 
void cf()
{
	//ll n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>a[i][j];
			//输入每一个点的高度 
		}
	}
	ll ans=-1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			ans=max(ans,1ll*dfs(i,j));
			//以i,j为起点的可以滑雪的最大距离 
		}
	 } 
	 cout<<ans+1<<endl;//注意这里要加1因为它自己本身滑到自己的话高度是1不是0这个非常坑 
	
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	ll t;
	t=1;
	while(t--)
	{
		cf();
	}
}

 

洛谷: 食物链计数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
const int mod=80112002;
vector<ll>g[N];
ll cnt;
ll du[N];
ll indu[N];
ll st[N];//表示以i为起点的最长的食物链是多少 
int dfs(int x)
{
	if(st[x])return st[x];
	if(du[x]==0)return 1;//如果以这个点为起点的点的出度为0说明以这个点为起点的食物链只有一条
	//说明不止一条
	ll sum=0;
	for(int i=0;i<g[x].size();i++)
	{
		sum=(sum+dfs(g[x][i]))%mod;
	 } 
	 st[x]=(sum)%mod;
	 return st[x];

}
void cf()
{
	ll n,m;
	cin>>n>>m;//生物的种类和被吃的关系图
	for(int i=1;i<=m;i++)
	{
		ll x,y;
		cin>>x>>y;
		indu[y]++;//入度y--; 
		du[x]++;//出度x++ 
		g[x].push_back(y);
		//x-y直接连接一条边 
	 }
	 ll ans=0;
	 for(int i=1;i<=n;i++)
	 {
	 	if(indu[i]==0)
		 {
		 	ans=(ans+dfs(i))%mod;
		  } 
	 }
	 cout<<ans<<endl;
	 
	  
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t=1;
	while(t--)
	{
		cf();
	}
}

 

还有一道几乎一样的题目洛谷的3183食物链不过这题要求不可以单独一个点去做食物链

这很好办我们只需要去再判断一下

判断出度必须大于0

这样就可以了

if(indu[i]==0&&du[i]>0)
		 {
		 	ans=(ans+dfs(i));
		  } 

洛谷猫粮规划

当然sum>r的时候可以剪枝

每一次pos==n的时候我们就回溯

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll n,l,r;
ll cnt;
ll a[N];
void dfs(int pos,int sum)
{
	//从pos的位置开始,总数是sum开始搜的时候的答案
	if(sum>r)return;
	if(pos==n)
	{ 
	if(sum>=l&&sum<=r)
	{
		cnt++;
		
	}
	return;//搜到一种的话就回溯 
}
	dfs(pos+1,sum);
	dfs(pos+1,sum+a[pos+1]);//下一个位置选或者不选 
	 
}
void cf()
{
	cin>>n>>l>>r;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	dfs(0,0);
	cout<<cnt<<endl;
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t=1;
	while(t--)
	{
		cf();
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值