记忆化搜索题目

洛谷P1216 数字三角形 Number Triangles

题目描述
观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

        7 
      3   8 
    8   1   0 
  2   7   4   4 
4   5   2   6   5 

在上面的样例中,从 7→3→8→7→5 的路径产生了最大

输入格式
第一个行一个正整数 r,表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

输出格式
单独的一行,包含那个可能得到的最大的和。

输入输出样例
输入

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5 

输出

30

说明/提示
【数据范围】
对于 100% 的数据,1≤r≤1000,所有输入在 [0,100]范围内。

代码

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int M = 1005;
int r;
int dp[M][M],a[M][M];
int dfs(int i,int j)
{
	if(i==r) return a[i][j];
	if(dp[i][j]>=0) return dp[i][j];
	return dp[i][j]=max(dfs(i+1,j),dfs(i+1,j+1))+a[i][j];
}
int main()
{
	memset(dp,-1,sizeof(dp));
	memset(a,0,sizeof(a));
	cin>>r;
	for(int i=1;i<=r;i++){
		for(int j=1;j<=i;j++){
			scanf("%d",&a[i][j]);
		}
	}
	printf("%d\n",dfs(1,1));
	return 0;
}

洛谷P1434 [SHOI2002]滑雪

题目描述
Michael 喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael 想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:

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

一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度会减小。在上面的例子中,一条可行的滑坡为 24-17-16-1(从 24 开始,在 1 结束)。当然 25-24-23-…-3-2-1 更长。事实上,这是最长的一条。

输入格式
输入的第一行为表示区域的二维数组的行数 RR 和列数 CC。下面是 RR 行,每行有 CC 个数,代表高度(两个数字之间用 11 个空格间隔)。

输出格式
输出区域中最长滑坡的长度。

输入输出样例
输入

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

输出

25

说明/提示
对于 100% 的数据,1≤R,C≤100。
代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100+5;
int r,c;
int h[N][N];
int dp[N][N];
int dir[4][2]={
	{1,0},
	{0,1},
	{-1,0},
	{0,-1}
};
int dfs(int x,int y)
{
	if(dp[x][y]!=0) return dp[x][y];
	int maxt=1;
	int t;
	for(int i=0;i<4;i++){
		
		int nx=x+dir[i][0];
		int ny=y+dir[i][1];
		if(nx>0&&ny>0&&nx<=r&&ny<=c&&h[nx][ny]>h[x][y]){
			t=dfs(nx,ny)+1;
			maxt=max(t,maxt);
		}
	}
	dp[x][y]=maxt;
	return maxt;
}
int main()
{
	
	
	int ans=0;
	memset(dp,0,sizeof(dp));
	scanf("%d%d",&r,&c);
	for(int i=1;i<=r;i++){
		for(int j=1;j<=c;j++){
			scanf("%d",&h[i][j]);
		}
	}
	
	for(int i=1;i<=r;i++)
		for(int j=1;j<=c;j++){
			dp[i][j]=dfs(i,j);
			ans=max(ans,dp[i][j]);
		}
	
	printf("%d\n",ans);
	return 0;
}

洛谷P1464 Function

题目描述
在这里插入图片描述
输入输出格式
在这里插入图片描述

输入输出样例
输入

1 1 1
2 2 2
-1 -1 -1

输出

w(1, 1, 1) = 2
w(2, 2, 2) = 4

代码

#include<iostream>
#include<cstring>
using namespace std;
const int N = 25;
int f[N][N][N];
int dfs(int a,int b,int c)
{
	if(a<=0||b<=0||c<=0) return 1;
	if(a>20||b>20||c>20) return dfs(20,20,20);
	if(f[a][b][c]) return f[a][b][c];
	
	if(a<b&&b<c) f[a][b][c] = dfs(a,b,c-1)+dfs(a,b-1,c-1)-dfs(a,b-1,c);
	else f[a][b][c] = dfs(a-1,b,c)+dfs(a-1,b-1,c)+dfs(a-1,b,c-1)-dfs(a-1,b-1,c-1);
	
	return f[a][b][c];
	
}
int main()
{
	int x,y,z;
	//freopen("data.txt","r",stdin);
	
	while(~scanf("%d %d %d",&x,&y,&z)){
		if(x==-1&&y==-1&&z==-1) break;
		memset(f,0,sizeof(f));
		printf("w(%d, %d, %d) = %d\n",x,y,z,dfs(x,y,z));
	}
	return 0;
}

洛谷 P2690 [USACO04NOV]Apple Catching G

输入格式
第一行2个数,T和W。接下来的t行,每行一个数,代表在时刻t苹果是从1号苹果树还是从2号苹果树上掉下来的。

输出格式
对于每个测试点,输出一行,一个数,为奶牛最多接到的苹果的数量。
输入输出样例
输入

7 2
2
1
1
2
2
1
1

输出

6
#include<iostream>
#include<cstring>
using namespace std;
int n,w,a[1005];
int f[1005][3][35];
int dfs(int i,int j,int k)//i为时间点,j为哪棵树,k为移动了多少次
{
	if(i>n) return 0;
	if(f[i][j][k]!=-1) return f[i][j][k];
	int t1=0,t2=0;
	if(k<w&&a[i]!=j)
		t1=dfs(i+1,-1*j+3,k+1)+1;
	t2=dfs(i+1,j,k)+(j==a[i]?1:0);
	return f[i][j][k]=max(t1,t2);
}
int main()
{
	//freopen("data.txt","r",stdin);
	scanf("%d %d",&n,&w);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	memset(f,-1,sizeof(f));
	
	printf("%d\n",dfs(1,1,0));
	return 0;
}

牛客网 简单拓扑dp

题目描述
(良心出题人wzc说这是个简单拓扑dp,它就必然是一个简单拓扑dp,wzc是不会骗人的)

wzc在一张拓扑图上,他所在的起始位置被标记为0。除了起始位置外,还有被1到n这n个整数所标记的n个顶点,每个顶点i都有一个正整数值xi。
这些顶点之间存在着m条有向边。题目保证图中不存在环,且从顶点0出发必定能到达顶点n。

wzc希望从起点0出发经过某条路径到达顶点n,并且收集经过的所有结点上的数字,使得所有数字的和最大。
现在请你帮wzc求出他能得到的最大数字和是多少。

输入描述:
第一行包含两个整数n,m(1<=n<=1e5,1<=m<=min(n*(n+1)/2,2e5))表示除了起点外的顶点的个数,以及有向边的条数。
第二行为n个空格隔开的整数xi,分别代表顶点1,顶点2,…顶点n上的数字。(1<=xi<=1000)
接下来m行,每行两个整数a,b(0<=a,b<=n),代表有一条有向边从顶点a指向顶点b。
输出描述:
输出一个整数,表示wzc能得到的最大数字和是多少。
示例1
输入

5 6
9 5 8 7 4
0 4
2 1
1 5
3 5
4 3
4 2

输出

25

代码

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxm=1e5+5;
int num[maxm];
int dp[maxm];
vector<vector<int>> edge;

int ans=0;

int dfs(int now,int target,int cost)
{
	
	if(now==target)
	{
	ans=max(ans,cost);
//	cout<<ans<<endl;
        return cost;
    }
    else if(dp[now]!=-1)
    {
    	return dp[now]+cost;
	}
	for(int i=0;i<edge[now].size();i++)
	{
	  dp[now]=max(dp[now],dfs(edge[now][i],target,cost+num[edge[now][i]]));
	}
	return dp[now];
}

int main()
{
	memset(dp,-1,sizeof(dp));

	num[0]=0;
	int n,m,x,y;
	cin>>n>>m;
	edge.resize(n+1);
	for(int i=1;i<=n;i++)cin>>num[i];
	for(int i=0;i<m;i++)
	{
		cin>>x>>y;
		edge[x].push_back(y);
	}
	dfs(0,n,0);
	cout<<ans<<endl;
	
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值